Ideally, a version control system is supposed to save you time and money. The purpose of a version control system is to enable development teams to track and protect all assets involved in the development of the application. Most important of these assets is the source code, but you also want to track changes to documentation, executables, graphics, and pretty much anything that is involved with the project.
Version control systems allow you to track all the changes made to a file. With this information, it is easy to restore a previous version of a file, if it is needed. Version control systems use security, to ensure that no unauthorized access is permitted to the system. Moreover, a version control system extends beyond just developers. Anyone involved in a project who uses a computer to manage project information can benefit from the use of a version control system.
There are many systems on the market today. Some are free and some are not. This section discusses three of the most commonly used systems today: Visual SourceSafe, CVS, and Subversion, and then introduces you to Team Foundation Version Control.
Visual SourceSafe (VSS) is a version control system from Microsoft for use with Microsoft Visual Studio. It is designed to be easy to use right out of the box, and to integrate effectively into Visual Studio. It also provides a command-line tool and separate IDE for accessing the system. VSS also is included with most MSDN subscriptions, making it a natural application to use alongside Visual Studio.
VSS includes the standard features of a version control system, including a repository (file-based), the ability to check files in and out, and the ability to branch and merge files. However, many people have had issues with VSS. VSS relies on file sharing, which can lead to a corrupt database if something happens while a file is being shared. VSS performance can also begin to degrade when a large number of files is involved. While VSS is suitable for small team use, you really need something more robust for larger teams and projects. Moreover, VSS is not easily extensible or easy to access over a slow network connection. This can make using VSS with distributed groups very difficult.
Most versions of VSS support exclusive check-out only, but the latest version VSS 2005, supports shared check-out as well, though it defaults to exclusive.
CVS started out as a bunch of shell scripts written by Dick Grune. It is a free open-source version control system, designed specifically for use with development projects. It has been around for a very long time, and as such has gotten a lot of use, mostly because it was the only free alternative out there.
CVS uses a file-based repository, similar to VSS. Like VSS, it tracks the history of individual files in the repository, and assigned revision numbers to individual files.
CVS is a command-line only version control system, though there is an offshoot of it called WinCVS that applies a graphical interface to CVS.
Subversion is a free open-source version control system that manages a list of files and directories. It was not built specifically for managing development projects. Instead, it is more of a general system that can be used for managing any files, from C# code files to your shopping list for Wal-Mart.
Subversion was actually built by developers who were looking for an alternative to CVS. They felt there were some severe limitations with CVS, and wanted to build something that, while staying true to the ideas of CVS, was more stable and less buggy. The point was to build something similar to CVS, so CVS users could easily switch, but not duplicate any CVS issues.
Subversion also uses a file-based repository. Unlike CVS however, it does not apply revision numbers to individual files. Instead, it applies a revision number to the entire file tree. In effect, each revision number is the state of the entire repository after a committed change.
Team Foundation Version Control (TFVC) is a brand new version control system, built from the ground up. Make no mistake; this is not just a newer version of Visual SourceSafe. It is a three-tier application, utilizing Web services and using SQL Server 2005 as the backend repository. It provides both a GUI and command-line tools for accessing the system. It has been designed for enterprise use and provides support for distributed teams. It provides a secure, reliable, and scalable architecture, scaling to well over two thousand users on a single server. Microsoft itself has said that it will move its development onto this platform in the future.
In addition to some of the standard version control features, TFVC has some brand new ideas and concepts. It integrates with the Team Foundation work item system, allowing you to associate checked-in files with work items. It provides atomic check-in capabilities, meaning that either all the files are checked in, or none of the files are checked in. In addition, it implements a new feature called shelving that allows you to store what you are currently doing on the server without checking the changes in.
TFVC is also extensible, providing a rich object model, as well as Web services, that can be used to access TFVC. Using this extensibility, specifically the Web services, partners have been able to leverage the use of TFVC on other platforms, such as Java and Linux.
As you will learn throughout this chapter, TFVC is the way to go for version control, especially with its integration into the rest of Team Foundation Server.
All version control systems, regardless of who makes them, have some common concepts. To truly appreciate Team Foundation Version Control, and to make the most of it, you need to have a general understanding of these concepts. In this section, you learn about those concepts. You see quickly how each of the previously mentioned systems implements those concepts, and then learn in more detail how Team Foundation Version Control handles them. In some cases, Team Foundation Version Control appears to handle things in a similar manner to one of the other systems, while in other cases it may seem to be a radical change. Regardless, by the end of this section, you should have a good understanding of version control system concepts. As well, you should have an appreciation for how Team Foundation Version Control handles these concepts. Then, in the next section, building off this information, you get some hands-on experience using Team Foundation Version Control.
The version control repository is the central store of data for the version control system. Any files that are added to the version control system are stored in the repository.
A version control repository can take on different forms. Subversion, for example, uses a file system tree, a collection of folders and files on a file share, as its repository, as does both CVS and Visual SourceSafe. Team Foundation Version Control, on the other hand, uses a backend database, as you will learn about shortly.
The whole point of a version control system is to be able to retrieve, view, and edit previous states, or versions, of files. Different version control systems track changes to files in different ways. However, Subversion, CVS, Visual SourceSafe, and Team Foundation Version Control all use a similar method, called reverse delta technology, for storing changes, which you will also learn about shortly.
The repository for Team Foundation Version Control is the SQL Server 2005 instance used by the Team Foundation Server. Everything related to the version control system is stored in SQL Server. This is an ideal situation for several reasons. By using a database backend, TFS makes use of transactions, to ensure that when you check in, either all the files check in, or none of them do. This is called atomic check-in; it allows SQL Server to make sure that the database integrity is maintained. As well, backing up your version control system is now as simple as running a database backup, and restoring is just as easy as running a database restore.
Within the TFVC repository, you have the root directory, represented by $/. Beneath that root directory are your different team projects. Inside each team project, you can have multiple folders and files, as shown in Figure 12-1.
This image shows a view of the Source Control Explorer window, which allows you to navigate the repository. As you can see, TFVC allows you to view and interact with the repository as if it were a bunch of files and folders, which conceptually makes it very easy to use. But, as pointed out above, in reality the repository is a database, with all the advantages that databases bring.
Figure 12-2 shows an image from SQL Management Studio of the tables in Team Foundation Server that are associated with the Team Foundation Version Control System.
All these tables are located in the TFSVersionControl database on the data tier of Team Foundation Server.
Team Foundation Version Control gives you a variety of ways to interact with it. With CVS and Subversion, the repository is generally accessed via a command-line tool, though there are some graphical tools available. Team Foundation Version Control can be accessed from directly within Visual Studio, utilizing the Source Control Explorer. There is a command-line tool that can be used for different options. In addition, developers can build applications off the Team Foundation Version Control Object Model.
Let's talk next in a little more detail about how Team Foundation Version Control stores changes in the repository. It uses a system called reverse delta technology, which turns out to be a very efficient system. Basically, only the latest version of a file is the full version. Any earlier versions of a file are stored as deltas of the latest version. When you apply this delta to the latest version, you are able to recreate an earlier version of this file. This is rather counterintuitive to most people. Most people would think that the first version of a file is the full version, and any changes made to the files after that are stored as deltas. But Team Foundation Version Control, as well as other version control systems, have found the reverse delta scheme to be a better methodology to follow. Because most of the time the version that is requested is the latest version of the file, you want the latest version to be the full version.
Finally, although you should always use the object model when writing code to interact with Team Foundation Server and Team Foundation Version Control, there are four Web services that are used by TFS to work with TFVC.
The Administration Web service can be used to kill processes on the server, change the server state, optimize the database, and retrieve repository and server information. The Integration Web service is used to delete projects, set up notifications, and retrieve artifacts from TFS. The ProxyStatistics Web service, as you would guess, returns information on the proxy server. The Repository Web service is the main Web service for accessing the Team Foundation Version Control system. It allows you to, among other things, check in items, delete items, and update items.
It is not advised that you build applications that use these Web services. These Web services are subject to change in future versions of Team Foundation Server. You should only build applications using the Team Foundation Server Object Model.
Have you started to figure out yet that every version control system does some things differently? Version numbers are no exception. In Subversion, every time you check in a file, a new version number is applied to all the files and all the folders in the repository. In CVS, each change to a file is a unique version number, same as in Visual SourceSafe.
Team Foundation Version Control introduces a new concept in place of version numbers, called the changeset number. Remember earlier we mention atomic check-ins, and how groups of files are either all checked in together, or none of them is checked in. These groups of files are referred to as changesets. Think of a changeset as an easy-to-manage entity containing all the related pieces of the project on which you have been working.
Changeset numbers are not tied to specific team projects. They are, in fact, a version number used for the entire repository. For example, you check in some files into Team Project 1, and those files are given a changeset number of 6. Someone else then checks in some files into Team Project 2. Those files are then given a changeset number of 7. If you then check more files into Team Project 1, those files will be given a changeset number of 8. So it is not uncommon to view the history of a file in Team Foundation Version Control, and see gaps between the changeset numbers, as shown in Figure 12-3.
This image shows the history for a particular file in the TFVC system. Notice the file has three different changeset numbers. Changeset 6 was when the file was initially added to the version control system. Changesets 33 and 36 represent edits to the file. Notice how the changeset numbers are not sequential. This is due to other files being checked into the version control system before these edits took place.
A workspace is where you keep the files and folders that you check out of the repository. It is basically a series of folder mappings on your workstation. Each mapping takes a folder in the repository and associates it with a local folder on your workstation. These mappings allow TFVC to know where to download code onto the local machine when it is checked out. The workspace itself is not just a folder on the local machine though. The workspace is an object, an entity that can contain multiple folder mappings. This allows you to have one workspace that can map all the different projects you are working on, or you could have a separate workspace for each project. Use whatever scenario works best for you.
Team Foundation Server stores your workspace definition on the server. This includes all the file and folder mappings associated with the workspace, version information, and status of the files in your workspace. This allows other developers, with the appropriate security permissions, to duplicate your workspace on their development machines. This can be an effective way to perform a code review or help a remote developer with a coding issue.
There are some rules to follow when creating your workspaces. You cannot map the same repository folder twice in the same workspace. For example, let's say you have a folder in the repository called Folder1. If you have already mapped this repository folder to a local folder, say LocalFolder1, then you cannot add another mapping for Folder1 to go to LocalFolder2, because TFVC would not know which local folder to put the files into. Also, you cannot map two different repository folders to the same local folder in a workspace. For example, you cannot map Folder1 and Folder2 from the repository to LocalFolder1.
Ok, that's enough generalities about workspaces. Let's look at how to actually manipulate these things. As usual, you can manipulate your workspaces using either Source Control Explorer or the commandline tools. If you open the Source Control Explorer, at the top of the window is a workspace drop-down list box. From that list box, select Workspaces to open the Manage Workspaces window, as shown as Figure 12-4.
This window allows you to add new workspaces, editing existing workspaces, or remove workspaces that are no longer needed. To add a new workspace, simply click Add. This opens the Add Workspace window, as shown in Figure 12-5.
As you can see, you can specify the name of the workspace, the workspace owner, and the computer on which the workspace will reside. As well, you can also specify comments. But of course, the real meat of a workspace are the working folders, the mapping of the local folders to the folders in the repository. In Figure 12-5, you have two projects mapped in this workspace. The BaseTeamProject is mapped to C:\Workspaces\BaseTeamProject, and the CustomCheckinPolicy is mapped to C:\Workspaces\ CustomCheckinPolicy. So the next time you go to retrieve files from the BaseTeamProject project, those files will be stored in the C:\Workspaces\BaseTeamProject directory on your local workstation.
You can do the same thing from the command-line tools. Using the Visual Studio 2005 command prompt (Start⇨All Programs⇨Microsoft Visual Studio 2005⇨Visual Studio Tools⇨Visual Studio 2005 Command Prompt), run the following code:
tf workspace /new MyCmdWorkspace /noprompt /s:<TFS Server Name>
This code creates a new workspace called MyCmdWorkspace on the specified Team Foundation Server. If you open the Manage Workspaces window after running this code, you will see the newly created workspace, MyCmdWorkspace. If you do not include the /noprompt flag, then the Add Workspace window will open, for you to confirm the creation of the workspace.
You can also use the command-line tools to map local folders to repository folders. After creating the above workspace, run the following code from the command prompt:
tf workfold /server:<TFS Server Name> /workspace:MyCmdWorkspace /map $/BaseTeamProject c:\Workspaces\MyProject
This command maps the BaseTeamProject project to C:\Workspaces\MyProject. You can verify this by viewing the workspace from the Manage Workspaces window.
When you check out a file from a version control system, you are making a copy of that file for you to work on. Once you have made your changes and are done, you add the file back to the repository. This is called the check-in process. All version control systems support check-in/check-out in some form or fashion.
There are two basic models for checking files in and out: exclusive or shared. The exclusive model, also known as pessimistic locking or the lock-modify-unlock model, is a method used by several version control systems, including older version of Visual SourceSafe. In this model, one person only can have a file checked out of the repository at a particular time. If User A checks out File A, then User B cannot check out File A until User A checks the file back in. While this ensures that two people can't make modifications to the same file at the same time, it is also a bit restrictive.
The shared model, also know as optimistic locking or the copy-modify-merge model, is a method used by VSS 2005 and Subversion. In this model, multiple people can check out the same file at the same time. So User A and User B can both check out File A at the same time. When the file is checked back in to the repository, the version control system will check to see if the file was updated in the repository while you had it checked out. If so, that means you no longer have the latest copy of the file, and you will need to merge your file changes into the latest copy. Most version control systems which support shared check-out provide you with a mechanism for merging these files.
Team Foundation Version Control provides you with the best of both worlds. You can choose to use either the shared or the exclusive check-out model, though it defaults to the shared model, and the shared model is the recommended way to go. It allows you more power and flexibility to achieve your development goals.
As mentioned earlier, the check-in/check-out process in Team Foundation Version Control is atomic. This means that all the changes are applied to the repository, or none of them is. Making use of transactions in SQL Server 2005, you are assured that this will occur. In addition, the check-in process is integrated into the work item tracking system of Team Foundation Server. When you check in your files, you can associate them with one or more work items. This allows you to always have a relationship between the definition of a problem and the code that fixes it. Also, you get e-mail check-in notification right out of the box, so you can be e-mailed any time files are checked into the repository.
Finally, you can define check-in policies. These policies define the rules that determine whether you can check your files into the repository. For example, one rule that ships with Team Foundation Server restricts the check-in process unless you have associated your code with a work item. You cover check-in policies in more detail later in this chapter, and will even learn how to build your own custom policy.
Let's look at some examples of checking files in and out of Team Foundation Version Control. There are several different ways to check out files. One way is to open a development project that is already associated with the version control system. When you then begin to modify files in the project, they will be automatically checked out for you as you begin to make your modifications. Another way is to right-click a file in the Source Control Explorer, and select Check Out for Edit... from the context menu. This opens the Check Out Window, as shown in figure 12-6.
This window shows you the file(s) you want to check out, and allows you to select the lock type you want to use. The default is none, which enables the shared model discussed earlier. You can also select Check Out, which is the exclusive model. Simply click the Check Out button to check out the file. The latest version of the file will be downloaded to your workspace. Simply double-click the file in Source Control Explorer to open and edit it.
Once you have finished editing your file(s), you will want to check them back into the version control system. You can either right-click the file in Source Control Explorer, and select Check In Pending Changes from the context menu, or you can open the Pending Changes window by selecting View⇨Other Windows⇨Pending Changes. Both options open windows with very similar functionality. Figure 12-7 shows the Pending Changes window.
This window gives you several options to consider before you check the files back in. You can click the Policy Warnings button to see if you are violating any check-in policies. You can click the Check-in Notes button to enter any check-in notes that are required. You can click the Work Items button to see a list of work items for your team project. You can then select one or more work items and associate them with this check-in. You can enter comments for the check-in, and even decide to shelve your changes until a later date.
One last thing to look at is the ability to resolve conflicts when checking files back into the system. Specifically, let's look at the scenario where you have checked a file out, and someone else checks out the same file. The second person makes a change to the file, and checks it back in. You then make a change to your copy, and go to check it back in. However, at this point, you no longer have the latest version of the file from the repository, so you are going to have some conflicts. When you click the Check In button, the Resolve Conflicts window appears, as shown in Figure 12-8.
This window is telling you that a newer version of the file you are trying to check in already exists on the server. As such, you are going to have to resolve this conflict. If you click the Auto Merge All button, it will attempt to resolve the conflicts for you automatically. If you click the Resolve button, it opens a new window, where you can decide how you would like to resolve this situation. You have the option of merging changes using the merge tool, undoing your local changes, or discarding the server changes. Figure 12-9 shows an example of the merge tool in action.
If you use Visual SourceSafe, this tool will seem very familiar to you. It allows you to go through each conflicting file, and choose what code goes into the final file, resolving your conflicts. Once all the conflicts are resolved, the new file is then saved into your workspace. You can then try to check the files in again, and they should check into the repository with no problems.
Branching is a way for you to isolate code into a separate area for development. It allows a collection of files to diverge on two or more different paths. There are several reasons you might want to branch your code. You might need to create a bug fix for a problem that was found in your production code. You might want to segment your application development into the different functional areas of your application. In this case, you would have a main folder, and then branch off that main folder for each functional area. In the best practices section later in this chapter, you learn some of the best ways to use branching in your environment.
Microsoft has recently published a primer on how to properly branch and merge code on MSDN. You can refer to the article here: http://msdn.microsoft.com/vstudio/default.aspx?pull=/library/en-us/dnvs05/html/BranchMerge.asp
Obviously, there are times where you will want to take your changes from your branch, and put them back into the folder from which you branched. Alternatively, you might want to take new changes from the original folder, and move them into your branch. This process is called merging. As you have seen in the previous section on check-in/check-out, Team Foundation Version Control has a nice merge process in place to help you walk through this merge process. In addition, the section later in this chapter on best practices discusses several concepts related to when you should merge different branches.
Team Foundation Version Control uses a method called the path space branching model. Basically, it creates new copies of items based on their path. This allows easy logical access to the branch, because you can think of everything in terms of files and folders. This is different from other version control systems, which use a version number branching model, where each branch has a different version number. The path space branching model is easier and more intuitive to use.
Let's look at some basic examples of how to branch and merge items in Team Foundation Version Control. Please note this is a rather simplistic example, which shows some basic branch and merge functionality. When you get to the best practices section later in this chapter, you see some more-detailed examples.
Follow these steps to create a new team project and console application to use for the following example:
Start off by creating a new team project called BranchExample. To do this, open Team Explorer, right-click your Team Foundation Server, and select New Team Project. This will start the New Team Project Creation Wizard. Simply follow the directions to create your team project,
Now create a console application called BranchTest. Select File⇨New⇨Project to open the New Project window. Select Visual C# as the project type, and Console Application as the template. Enter BranchTest as the name of the application, check the Add to Source Control check box, and click OK to create the project. When prompted to select a team project location, select the BranchExample Team Project.
Finally, check the console application into version control. Open the Pending changes window by selecting View⇨Other Windows⇨Pending Changes, and click the Check In button, to check in the application.
Open the Program.cs file, and add the following comment to the Main method:
//Comment added from main folder of version control system.
Open the pending check in window and check this new change into the version control system. Open Team Explorer, open the BranchExample Team Project, and double-click the Source Control icon to open the Source Control Explorer. If you open the BranchExample folder in Source Control Explorer, you'll see the folder for the BranchTest project you were just making changes to.
Next, let's create a branch off this BranchTest folder.
Right-click the BranchTest folder, and select Branch from the context menu. This opens the Branch window, shown in Figure 12-10.
This window shows you the source folder or file you are branching from. In this case, it is $/BranchExample/BranchTest. It then allows you to select the Target, which is the new branch that you want to form. You can either type in the new branch, or select the Browse button to use a graphical interface. For now, simply accept the default name and location for the branch.
You have five different options for creating your branch. You can select a specific changeset, date, or label to branch from. You can branch based off a workspace version. Or you can take the default, which is to branch off the latest version of the code in the repository. You can also have the branch files automatically downloaded into your workspace. For this example, leave everything as the defaults, and click OK.
Figure 12-11 shows the new branch in the Source Control Explorer window.
Once you have created your new branch, you have a bunch of files in your Pending Changes window that need to be checked in to complete the branching process. Open your Pending Changes window and check those changes back in.
So now you have two folders in your Team Project, BranchTest and BranchTest-branch. Next, you want to modify a file in the branch so you can merge it back. Using the Source Control Explorer, navigate to the BranchTest-branch folder in the BranchExample Team Project, and double-click the BranchTest.sln to open the console application. Then double-click the Program.cs file to open it and add the following comment:
//I am a comment from the branch
Save your changes, then open the Pending Changes window and check your changes back into the branch. At this point, you are now ready to merge the branch back with the original folder.
In the Source Control Explorer, right-click the BranchTest-branch folder and select Merge. This starts the Source Control Merge Wizard, as shown in Figure 12-12.
From this window, you can specify the source branch and the target branch. Notice that the target branch defaults to the parent folder that you branched from. Click Next to go to the next step of the wizard. On this page is a drop-down list box where you can select which version of the branch you want to merge. Keep the default of Latest Version and click Next; then click Finish to perform the merge.
Again, as when you branched earlier, you have to check the merged files back into TVFC. Open the Pending Changes window and click the Check In button to check in the changes. If you now navigate to the Program.cs file in the BranchTest, right-click the file, and select View, you will see the comment from the branch has been merged back into the main folder, as shown in Figure 12-13.