Visual Studio 2010 Team Foundation Server (TFS 2010) is an enterprise-level product for managing software projects throughout the entire application lifecycle. A major requirement of TFS is source-code control, which enables developers to store code in a central repository. Source control implies version control, which keeps track of every change that has been checked in by developers. Version control allows many developers to work on the same project and the project's source-code files with a reduced risk of lost code or overwriting other developers' changes. Because source control is a core need of developers, often IT departments initially bring TFS into their organization for its source-control capabilities. For more information on TFS 2010, see "Improve Build Management with TFS 2010 Build Services"and "Team Foundation Server 2010: A Brief Overview."
Source control is essential in large enterprise applications that have many different release versions of a product. Being able to support different versions of an application by using branching strategies and linking code changes to work products is where TFS's source control hits its stride. Here I'll delve into the features of TFS's source control and the intricacies of those features that are important to know but might not be easily apparent to developers using the product.
Visual Studio 2010 comes with Team Explorer, which is an interface to TFS and team projects. Team Explorer provides a fully integrated tool for
managing team projects, work items, view reports, builds, security, and other aspects of team development. Each team project has a Source Control
folder for viewing and managing source code, as shown in Figure 1.
Figure 1: Source Control folder in TFS 2010 Team Explorer
Double-clicking this folder opens Source Control Explorer, which contains all source folders and files included in a team project. Source Control Explorer is where most source-control-related functions can be performed. These functions include the following:
- Add files
- Branching and merging
- Check-in/check out
- Compare files and folders
- Get latest version/Get specific version
- Move/delete/rename files and folders
- Undo pending changes
- View history
I will cover most of these features in this article. But first, I'd like to discuss an area that confuses many people who are new to TFS: the concept of workspaces and what you must do to get source control to work with the local file system.
A workspace is a mapping of files on the server to a local area on a drive. Without a workspace, you cannot get files or add files to source control. A workspace is tied to a TFS server collection, local computer name, and username. This means that an individual computer can have more than one workspace as long as at least one of the three required items is unique. By default, a workspace is private, meaning no one can access the workspace other than the owner. However, it is possible to change the permissions on a workspace to either allow others to see and interact with a workspace or allow others to have full control over someone else's workspace. The owner of the workspace must manually set its permission if it is set to something other than private.
A workspace can have one or more mappings of folders in source control to locations on a local machine as long as the locations are unique. For
example, the mappings in Figure 2 are allowed, whereas the mappings in Figure 3 are not allowed. The mappings in Figure 3 are invalid because the
mapping for SecondApplication in the second row is not unique, since it is already mapped in the first row.
Security in TFS's source control is very granular. It is possible to set permissions down to the individual file level. A user can only interact with a folder or file in source control based on the permission level given to the TFS or Windows user or group to which the user is assigned. Here are the available permissions:
- Administer labels
- Check in
- Check in another user's changes
- Check out
- Manage branch
- Manage permissions
- Revise another user's changes
- Undo another user's changes
- Unlock another user's changes
Checking Out a File
When a user wants to work on a file, the file can be checked out either through Solution Explorer or Source Control Explorer. When the file is checked out, there are three versions of the file: server version, workspace version, and local-file version. At the moment the file is checked out, all three versions are the same. However, when you change the file locally, the local version is now different from the workspace and server versions. The workspace version is the version of the file at the point when it is checked out, and the server version is the current version of the file on the server. If someone also checks out the file into his or her workspace, makes changes, and checks it back in before you check your file in, there are now three different versions of the file: The server version is different from your workspace version, and your workspace version is different from your local version.
Having the various versions available is useful when you perform file compares. You can compare your local file to the workspace version to see the differences between the local file and version of the file at the time of checkout. If someone else made changes to the file and checked it back in before you did, you can compare the workspace version to the server version or compare the local version to the server version. Such comparison provides valuable information when you need to track down changes made to a file.
When a file is checked out to a workspace, it is a pending change. The server knows the file is checked out, but the changes will not be saved to the server until the file is checked in. The Pending Changes window helps manage your checkouts.
Pending Changes Window
The Pending Changes window is a one-stop-shopping location where you can view and manage all the files that are checked out in a workspace. The primary function in this window is to check in one or more files. When one or more files are checked in at the same time, a changeset is created. A changeset is assigned an ID and is also considered a version in TFS.
When you right-click a file or folder in Source Control Explorer and select View History, all the changesets for that file or folder are displayed. If a changeset is opened in history, all the files associated with that changeset are shown. From here, you can compare the individual files in the changeset to other versions of the file, see what work items the changeset is associated with, see any check-in notes, and view check-in policy warnings. All this information is saved when the files are checked in.
Checking In a File
In the Pending Changes window, you can check in multiple files at the same time and set check-in notes and work-item associations. When a file is checked in, two events may occur to prevent the check-in.
The first event is a failed check-in policy. A check-in policy is set by an administrator of the team project and could include any of these allowed activities:
- A builds policy prevents checking in any files in code that is in a working folder of a build definition that is triggered as continuous integration or by a rolling builds trigger. If a user's check-in breaks the build, anyone else who tries to check in a file within the build definition's workspace will receive an error message preventing the check-in. Other users cannot check in their code until the user who broke the build checks in a fix and it builds successfully.
- A changeset comments policy requires the user to provide check-in comments.
- A forbidden patterns policy prevents checking in files that have forbidden filename patterns in the server path of the file.
- A work items policy requires that one or more work items are associated with the check-in. This is a crucial requirement for enabling traceability from requirements down to the code.
- A work item queries policy requires that each changeset is associated with one or more work items from a specific work item query.
It is possible for a user to override check-in policies. However, if you allow this, it's advisable that you also set up an alert so that an admin or team leader is notified when someone overrides a policy.
The second event is a conflict occurring when a file is checked in. This happens because by default, more than one user can check out a file at the same time. This is known as a shared checkout. When someone checks in a file before you, when you try to check in the file and your changes conflict with the other person's changes, a conflict warning will appear. The check-in will not be able to proceed until the conflict is resolved. There are four options for resolving conflicts:
- Accept the server version.
- Accept the local version.
- Merge the changes using the merge tool.
- When possible, allow an auto merge if Visual Studio decides there are no overlapping changes.
As you might guess, merging is rarely easy and is never fun. The merge tool that comes with Visual Studio makes the task more manageable, but there's no getting around having to surgically select where changes are added if overlapping changes exist.
There are three ways to avoid dealing with merging. First, if the user is the first one to check out the file, you can select an option at checkout
time to prevent others from checking out the file until it is checked back in. A second, sneakier way is to use an option that allows others to check
out the file but does not let them check it back in until the first person who checked it out checks it back in. These options are available in the
checkout window shown in Figure 5.
A third way is to prevent shared checkouts at the team project level. This is not advisable in most scenarios because usually more than one person will need to work on a file at the same time.
A shelveset is a way to put your code on the server without checking it in to the main repository. There are many uses for this capability. For example, at the end of the work day, code that is checked out is not yet ready to be checked in. To keep this code safe, shelving it will guarantee that the code remains on the server without affecting anyone else. Another use is in peer reviews where you shelve your code and tell the reviewer to take a look at it. The reviewer can pull down the shelveset to the local machine, and the reviewer's files will be replaced with the shelved files. When the review is finished, the reviewer can either undo the pending change or shelve the checkout again. Either way, the files revert back to the original versions.
In situations where there are chronic build breaks, gated check-in provides a way to mitigate the problem. New to TFS 2010, gated check-in is a build definition trigger that kicks off a build when a check-in is attempted. If the build breaks, the code is not checked in. Gated check-in takes advantage of shelving to perform a build on the build server without checking the code in to the main repository first.
Gated check-in works via a trigger. When a user attempts to check in one or more files, TFS looks at the files to determine whether they are part of a workspace of a build definition that has a gated check-in trigger. If TFS finds one or more build definitions, a window prompts the user to select the build definition to run. The code is then shelved. The build starts by first getting latest files for the workspace of the build definition, then overlays the shelved files on top of the files in the workspace. The build is run, and if it passes, the files are automatically checked in. If it fails, the user is alerted about the failure and nothing is checked in.
Annotation is an effective way to see the history of a file at the code level. Right-clicking a file and selecting Annotation opens the file, showing
the changeset IDs and where the changes are in the file. Here, the user can select a changeset ID, and the changeset details window will open. Figure 6
shows an annotated file with two changeset IDs.
Figure 6: Using annotation in TFS's source control
Branching and Merging
Branching is useful when you need to support multiple versions of an application. When a folder is branched, TFS makes a copy of its contents and
places the copy in the target location. A branching relationship is established between the source and the target. Figure 7 shows a common branching
structure that supports two iterative development branches that were created off of "Main" and a release version that was also created off of "Main."
TFS 2010 includes a new branch visualization feature. For example, folders that are part of a branching relationship can have a different icon to
Figure 7: Branching structure example
TFS 2010 also includes branch visualization as an aid for tracking changesets as they are merged from branch to branch. Figure 8 shows how changeset 36
relates to the other branches. Changeset 36 first merges to Iteration1. Changeset 36 then merges to Iteration2, and finally to Version1. If a changeset
has not been moved to a branch, the target will not show a changeset ID.
Figure 8: Tracking a changeset
In the visualization window, you can perform a merge by dragging the changeset to the target. After you do so, you will see the Source Control Merge
Wizard, shown in Figure 9.
Figure 9: Using the Source Control Merge Wizard
Note that the wizard will still force you to either merge all changes up to a specific version or select a specific changeset. This can be confusing since dragging the changeset to a target normally means you want to merge that specific changeset only. It seems less efficient to have to choose the changeset manually in this scenario.
Timeline tracking, another visualization feature in TFS 2010, displays a sequential path for a changeset as it merges to other branches. Figure 10
shows the progression of changeset 36 in a timeline format. As you can see, the visualization features help manage the complexities of branching.
Figure 10: Timeline tracking
Control Is a Good Thing
Version control is a key ingredient for managing your application's lifecycle and ensuring a successful project. By fully integrating source control into the development process, development teams can understand what code changes relate to work items, what changes are included in a build or release, and how to manage different versions of code. Version control is also a good vehicle to introduce TFS to your enterprise. There are many tools available for migrating code and history from other version control systems to TFS. Getting your developers used to using TFS's version control will make it easier to introduce other enterprise-level features of TFS later. In many situations, this phased approach to bringing TFS into an organization is the most preferable and realistic option.
Brian Minisi is an ALM Ranger and a software architect for Computer Enterprises, Inc. (CEI), a consulting company specializing in Microsoft technologies. Follow him on Twitter: @brianminisi.