The first thing to understand is that the TFS model of the version tree is different from what you may be used to. It's at an extreme end of the spectrum.‡
I've used Subversion for a couple years now, and love the way it works. I always set up three folders under each project, Trunk, Tags, and Branches.
What you think of as "tags, branches, and trunks" are all represented by folders in TFS. A "trunk" is a folder that was created by a simple add, not as a branch of another folder. A "branch" is a folder that's derived from (and henceforth related to) another folder elsewhere in the system via the Branch & Merge operations. TFS doesn't have "tags" per se; the closest analogue is to create a branch based off of a historical version (via changeset number or label). Once again, this becomes yet another folder.
When it comes to managing your local workspace, the concept that "everything's a folder" is good news. If you want to create arbitrarily complex views on tags/branches/trunks, in the TFS world that task reduces down to the very simple problem of mapping local paths <-> server paths.
Of course, that doesn't mean you should. Disk space is a lot cheaper than network bandwidth or server CPU cycles. More importantly: the more complex your mappings, the more likely you are to accidentally commit the wrong file to the wrong place. My usual recommendation is:
- Create one workspace per branch/tag that you actively work on.
- In each workspace, create just one recursive mapping to the root of the branch.
- If this is not possible due to the size of the branches, avoid cloaks. They aren't a good solution because they won't stay in sync with folder adds/renames made by other people. Better to use a one-level mapping to the branch root + additional recursive mappings to the folders you need.
- If this is not possible because you have build-time dependencies not contained in the branch, shame on you :) Add the fewest # of additional mappings out to common libraries as possible.
- Ensure the relative paths are the same within each branch. (And if they change, the changes in structure propagate in lockstep with the changes to your makefiles.)
- Create one additional workspace for what I'll call "maintenance" tasks.§
This strategy provides:
- Zero resource overhead. No redownloading required when you context-switch.
- Low mental overhead. To start working on another branch, just open the other copy of the solution from disk. Or change the Workspace dropdown in Source Control Explorer.
- Low chance of screwups. Because branches are confined to their own workspace, clicking Checkin All will never commit changes that were pending in another branch...or worse, you can't accidentally make changes to the "release" branch that were intended to go against the "unstable" version.
What I want to do is have the root "Project/Website" folder on my hard drive, and be able to have it point to (mapped to) either tags, branches, or trunk, depending on what i'm doing, without having to screw around with fixing Visual Studio project references.
This is possible too. As mentioned you're just trading disk space for bandwidth/CPU. No big deal if your infrastructure supports it. I personally would find it too limiting in terms of parallel development, plus a higher chance of screwups -- but it's only natural a person raised on SVN might feel differently.
Here are the steps:
- Create one workspace. Map it to the branch/tag/trunk you intend to work on next.
- Follow all the other guidelines above.
- When it's time to change branch/tag/trunk, reopen the Workspace dialog and point the same local folder to the new server path.
- Get Latest.
- Starting in TFS 2008, the client will automatically prompt you to run Get anytime you make a change like this.
- Starting in TFS 2008 SP1, there is an even better way. Click "no" on the prompt, then run tf get /remap. This will only download the diffs between the two branches. This can be a huge bandwidth/CPU savings depending on folder size and how closely related they are. (Could actually take more server CPU on folders that are very small, very distantly related, or [of course] not related at all; use good judgment. Should always take strictly less bandwidth, though.)
‡In TFS, when you create a branch, it appears to the user as a brand new folder hierarchy. Put another way: when you look at the repository a priori, there's no clear way to distinguish "real" files/folders from branches. And frankly there isn't much difference. A "branch" is just another item, one that happens to have >=1 pieces of merge history metadata associated with it. Plenty of TFS commands depend on said metadata, and you can certainly query for it directly, but it won't show up in a simple tf dir. Meanwhile, because every branch occupies a unique position in path space, that means it's no more or less complex to uniquely specify a branched versionspec. $/path;changeset is sufficient, just like any other item.
CVS takes the opposite approach. When you branch, the path doesn't change. What you've done instead is bifurcate the versions along another dimension. This makes simple cases very easy to visualize: there's just one tree. Of course, you've only shifted the complexity elsewhere. When you want to uniquely specify a version of an item, knowing a path and a revision number isn't enough anymore; you need to know the branch too. And what if you rename a file in one branch but not another? In TFS nobody would care until it was time to merge the branches; in CVS just viewing the repository raises the issue. I'm sure you can think of other subtleties -- I'm not familiar enough with it to know how it handles every edge case.
Most SCC systems lie somewhere between these extremes. Let's call TFS 2005/2008 the far "left" and CVS the opposite "right."
Subversion sits basically atop TFS at the "left" pole. While the implementations are very different, the user's view of branching is almost identical now that merge tracking is finally implemented. (One could argue that prior to v1.5, it was even a little bit farther left than TFS. Branches were simply copies with low-level optimizations; the user had no way to query for relational metadata. SourceSafe falls into this same category, if not even farther left due to lack of systemwide version numbers.) Users coming from the SVN world shouldn't have a hard time once they understand the client/server workspace model and rejigger their terminology. (SVN has a lot of CVS baggage in its terms, eg the word "tag"; in fairness TFS inherits some verbal crud from VSS, eg the pervasive use of "checkin/checkout" despite being edit-merge-commit by default.)
Perforce is one notch to the right of TFS. Their underlying model is identical. They have the additional concept of branch specifications which meet some common user scenarios -- eg quickly knowing "which folders represent branches", shortcuts for specifying branched versionspecs w/o needing the full path -- but it's just syntax sugar.
TFS 2010 lies another couple notches to the right. Like Perforce they've created a store of "branch objects" that exist independently from (but map back to) the repository tree. Each branch also knows its relationships (eg parent, child, baseless) within a user defined branch hierarchy.
I'd place ClearCase about 2/3 of the way to the right. Complex branching scenarios fundamentally happen in version space from the server's point of view. However they have an extremely powerful system of "views" layered on top. As a result, the structure the user actually sees might be manipulated to resemble path space, or some hybrid. A similar level of customizability applies to their local workspace mappings.
Most other "enterprise" SCMs are about 3/4 of the way to the right. (eg AccuRev, MKS, StarTeam) Users can typically view the repository + branch tree in a variety of powerful ways, but can't configure system itself as flexibly as CC. This is probably a good thing :)
CVS is on the far right as described earlier. Ditto its ancestors RCS and SCCS.
Classifying distributed systems like Monotone, BitKeeper, and their derivatives is beyond the scope of this answer :)
§A couple newer operations in TFS can be done without a workspace at all:
- Creating a branch (tf branch /checkin - requires 2008 SP1)
- Destroying items (requires 2008)
A few others require mappings into a workspace, but don't require you to download any files:
- Deleting items
- Locking items
- Creating a branch the old way (tf branch /noget - available since 2005 early betas)
A few more require partial mappings and/or partial downloads:
- Merge requires only the target path to be mapped & downloaded.
- Rename requires both paths to be mapped and the target to be downloaded.
- Undelete /newname works like Rename.
I prefer to do these kinds of operations in their own "maintenance" workspace, isolated from my day-to-day development. Having their own workspace also means I can map huge parts of the repository in one fell swoop without actually downloading them. (On the contrary, in your "development" workspaces it's a best practice to run Get w/o any restrictive path scopes.) And as I've mentioned a few times now keeping the local <-> server mapping broad & simple means relative paths stay constant, references don't break, files don't get accidentally committed or committed to the wrong place; everyone is generally happier.
YMMV.