Four open source version control systems compared Version control used to be practically synonymous with CVS, but those days are well behind us now. In fact, you not only have an abundance of systems to choose from, you also have two distinct models of source code management to consider. In this article John Ferguson Smart test drives four popular open source version control systems and summarizes the pros and cons of each one.Version control is a critical aspect of any software project, and its importance should not be underestimated. At the risk of sounding overly dramatic, the choice of version control system can literally make or break a build process. A good source code management (SCM) solution blends into the development lifecycle, seemingly a natural extension of the developer’s tool set. A poorly adapted solution, on the other hand, can easily make life hell for the development team. At worst, it can be a powerfully dissuasive influence on good development practices such as refactoring, frequent commits, and continuous build strategies.In the interest of excellent version control, this article introduces you to four leading open source version control systems. The veteran system is CVS, so I’ll start with that, followed by its would-be replacement, Subversion. Next, I’ll introduce you to Bazaar and Mercurial, two systems that take a distributed rather than a centralized approach to SCM. The actions involved in version control don’t vary much from system to system, so I’ll use a single example (the Java Petstore application from Sun) to walk you through common development scenarios using each product. I’ll offer some observations about each, and then leave you to make your own decision based on what you’ve learned. Before I delve into all that, let’s review why reliable version control is crucial to the success of your application development process.Why you need version controlVersion control systems serve several key purposes. First of all, they allow you to safely store successive versions of your source code. In addition to providing a secure backup copy of the source code, this ensures you can back-track to a stable version if things go horribly wrong (which, as you likely know, they sometimes do).Version control systems also help team members work simultaneously on a project’s source code without stepping on each other’s toes, or crunching each other’s code. This can be done in several ways. One way involves locking a file when a user is working on it, so that other users cannot modify it at the same time. This is known as the “Lock-Modify-Unlock” model. The opposite of this approach allows developers to modify the same file simultaneously, and then merge the modifications into a new version containing changes from both developers. This second approach, known as “Copy-Modify-Merge” is more common in open source version control systems, because it is more aligned with the culture and practices of open source development. Version control systems also help to identify particular versions (or revisions) of your project, such as a particular product release.Finally, version control systems make it possible to create a new branch of your application source code, and work on this branch without compromising the stability of the original version. For example, you might release a stable version of a product even as your team continues to work on a parallel development branch. At a later date, you will integrate the changes into the main product branch and release a new stable version of the product.Points of comparisonIn the next sections I will introduce you to four version control systems capable of handling all the functions listed above. These products are too rich and complex to do justice to each of them in the space of a single article. Rather than attempt that, I’ll use Sun’s Java Petstore application example to take you through a short test drive of each of them. The first thing you typically need to do with a version control system is add your source code to the repository. Next, you need to obtain a copy of the latest version of the project from the repository. Then you might make some modifications and update the repository. If another developer has simultaneously made modifications to the files there are two possibilities: the system could integrate the changes successfully, or you might have to resolve a merge conflict manually. At some point, you will want to identify a particular release by placing a unique label (or “tag”) on that version. Later on, you will want to create your own separate branch of the code base, make some modifications, and then reintegrate the changes into the main branch.To summarize, you can evaluate a version control system based on how it handles imports, exports, modifications, updates, merging, tagging, and branching. You’ll probably also be interested in things such as ease of use, performance, and whether the system supports binary file types and atomic commits (which I’ll explain later). In the next sections you’ll see how CVS, SVN, BZR and Mercurial handle these steps, which should give you a practical idea of how each one copes in day-to-day use. It should also give you feel for which version control system best suits your needs.For point of reference, you may want to download Java Petstore 2.0 before we begin. Getting started with CVSCVS is an open source version control system that has been around since the 1980s, and is still used by many organizations today. It uses a client-server architecture, with files stored on the server in the form of RCS files (RCS is the “even more archaic than CVS” version control system on which CVS is built).Before you do anything in CVS, you need to tell it where to find the CVS server. You usually do this by setting an environment variable called CVSROOT: $ export CVSROOT=:pserver:john@cvs.mycompany.com:/usr/local/cvs Next, you need to logon to the server: $ cvs login (Logging in to john@cvs.mycompany.com) CVS password: CVS uses a fairly simple (and somewhat limited) authentication system, based on the Unix user accounts and groups defined on the server. To add your project to the CVS repository, you use the cvs import command: $ cvs import javapetstore START-REF START -m "Initial import" Handling binary filesThe standard cvs import is simple enough, but it usually won’t be sufficient for any non-trivial contemporary Web projects. The major complication with CVS is that it handles binary files poorly. CVS is fundamentally designed to cater to text files, and by default it assumes that anything you add is a text file. If you don’t tell it otherwise, CVS will assume that your JARs and GIFs are text files, and it may even try to merge them! Needless to say this can lead to data corruption. The safest thing to do is import an empty directory structure, and then add the files afterward. You have to be sure to let CVS know when you are importing binary files, using the -kb option shown here: $ cvs add -kb logo.gif Note that if you’re truly committed, it is possible to configure CVS to recognize binary files based on file name, by modifying the server configuration, but the process is a little too complex to go into here. Rudiments of version controlAfter placing your project in CVS you need to check out a working copy. This is the copy of the project that you will use in your day-to-day development — once you have imported the original directory into CVS you can discard it.Listing 1. Checking out a local copy of javapetstore $ cvs checkout javapowerstore cvs checkout: Updating javapetstore U javapetstore/3RD-PARTY-LICENSE.txt U javapetstore/bp-project.xml U javapetstore/build.xml U javapetstore/index.html cvs checkout: Updating javapetstore/bp-project U javapetstore/bp-project/app-client-ant.xml U javapetstore/bp-project/app-server-ant.xml ... Once you have your local copy, you can work more or less normally. You can use commands like cvs add and cvs rm to add and remove files from the repository. Here’s a typical cvs commit: $ cvs commit -m "Fixed bug #123" Before committing your changes, however, you generally update your local copy to download any recent changes. If another developer has changed one of the files you have modified, CVS will attempt to merge the changes. If it can’t manage a merge, it will let you know in no uncertain terms, as shown here: Listing 2. Updating javapetstore in CVS — conflicts found$ cvs update cvs update: Updating . RCS file: /usr/local/cvs/javapetstore/index.html,v retrieving revision 1.2 retrieving revision 1.3 Merging differences between 1.2 and 1.3 into index.html rcsmerge: warning: conflicts during merge cvs update: conflicts found in index.html C index.html cvs update: Updating bp-project When you edit the file in question, the conflicting lines are indicated as follows:Listing 3. CVS reports an error <<<<<<< index.html p.copy {text-align: right} ======= p.copy {text-align: center} >>>>>>> 1.3 Once you correct the conflicting lines, you can commit your changes normally.Tags and branchesIn version control systems, tags are used to identify particular versions of your application. In CVS, you can tag a set of files using the cvs tag command, as shown here: Listing 4. Tagging in action, via the cvs tag command $ cvs tag release-1-0 cvs tag: Tagging . T 3RD-PARTY-LICENSE.txt T bp-project.xml T build.xml T index.html cvs tag: Tagging bp-project T bp-project/app-client-ant.xml T bp-project/app-server-ant.xml T bp-project/app-server.properties T bp-project/build.properties ... You use a similar approach to create a new development branch. Branches are used to allow work to continue on one stream of development (such as a new release) without affecting work on another stream (such as an existing production release).Listing 5. Branching in CVS e$ cvs tag -b release-1-0-patches cvs tag: Tagging . T 3RD-PARTY-LICENSE.txt T bp-project.xml T build.xml T index.html cvs tag: Tagging bp-project T bp-project/app-client-ant.xml ... Architectural issues with CVSAn overview of CVS wouldn’t be complete without mentioning some of the downsides of using it. Here’s a short list most developers would agree to:Slow tagging and branchingDifficulty renaming or moving directoriesLack of atomic commitsPoor support for binary file formatsUnlike most modern version control systems, CVS does not support the notion of atomic commits. In a version control system that supports atomic commits, modified files are submitted to the repository not individually, but as a group (also known as a “change set”). If the changes cannot be correctly merged into the current source code in the repository, or if the update fails at some point (for example, if there is a network failure), then the commit is aborted and no modifications are made to the repository. This ensures that the source code in the repository is always in a coherent state. When you commit a set of changes in CVS, you have no guarantee that all of your changes will be correctly incorporated into the repository. If a commit fails for some reason, the source code on the repository may well be in an unstable state. This is a major architectural flaw.Many developers also balk at using CVS tags and branches for large-scale development projects. Updating each file one-by-one can be a time-consuming process. For example, if your project contains 1,000 files, CVS will go through your project and individually tag each one of them, which requires a separate network transaction for each tagged file. For a very large project, this process can take hours.Like COBOL, CVS is a legacy system that is still widely in use. Nonetheless, CVS’s old-fashioned architecture makes it a poor solution for modern development processes, where agility and flexibility are of the essence. Most developers today, given a choice, would go with a newer solution like Subversion, Bazaar or Mercurial. Out with the old, in with SubversionSubversion is a relatively new product explicitly designed to overcome the known shortfalls of CVS. It is a well designed software package, boasting modern features such as atomic commits, fast branching and tagging, the possibility to rename or move files and directories, support for binary files, and lightweight network transactions. Another nice feature of Subversion is that it is easy to set up an Apache server to provide HTTP (or HTTPS) access to your repository, so you can browse your repository using an ordinary Web browser. Subversion also provides a more sophisticated authentication model than CVS, and allows more fine-grained control over user rights.One of the principal differences between Subversion and CVS is the way the two systems keep track of changes. CVS is a file-based system that maintains a separate version history for each individual file. Subversion, on the other hand, keeps track of revisions. A revision can be thought of as a snapshot of your project directory structure and contents at a given point in time. Revisions are the cornerstone of Subversion’s atomic updates. Updating the Subversion repository is a bit like updating a relational database using transactions: when you commit a set of changes, you are guaranteed that either all of your changes have been integrated into the repository, or none at all have.An offshoot of this strategy is that a given set of changes can be viewed as a distinct bundle and attributed to a particular developer. It also makes for more efficient handling of binary files and for much faster tagging and branching. This notion of atomic updates is painfully absent from CVS. As a result, in CVS, if a commit fails or is interrupted for some reason, the repository can be left in an unstable state: some files will have been correctly updated, whereas others will still be in their previous version. Subversion in actionThe Subversion commands are quite similar to those used in CVS, which ensures a CVS user will not feel too lost when getting started with Subversion. Importing a project into a Subversion repository looks something like this:Listing 6. svn import $ svn import . http://svn.mycompany.com -m "Initial import" Adding trunk Adding trunk/javapetstore Adding trunk/javapetstore/setup Adding trunk/javapetstore/setup/sql Adding trunk/javapetstore/setup/sql/javadb Adding trunk/javapetstore/setup/sql/javadb/delete.sql Adding trunk/javapetstore/setup/sql/javadb/cities.del ... Adding trunk/javapetstore/web/images Adding (bin) trunk/javapetstore/web/images/purple-jellyfish-med.jpg Adding (bin) trunk/javapetstore/web/images/fish3.gif Adding (bin) trunk/javapetstore/web/images/california-desert-tortoise.jpg Adding (bin) trunk/javapetstore/web/images/CIMG9129-s.jpg ... As you can see in the above example, Subversion automatically recognizes binary file formats and handles them appropriately.Directory structureThe presence of a trunk directory in the above code hints at another important difference between CVS and Subversion. By convention, all branches (including the main branch, or trunk) are stored in separate directories in Subversion, as are tags. The recommended Subversion directory structure is to create three subdirectories in the project root directory, as shown here: + trunk + branches + tags In practice, you can set up your directory structure in one of several ways. If your projects are very separate, and you want different tags and branches for each project, you might opt for a structure like this one: + myproject1 + trunk + branches + tags + myproject2 ... If all the projects in a repository are intimately related, you might prefer the following: + trunk + myproject1 + myproject2 ... + branches + tags Programming operationsLike CVS, Subversion expects you to check out a working copy for your day-to-day programming, like so:Listing 7. Checking out javapetstore in SVN $ svn checkout http://svn.mycompany.com/trunk javapetstore A javapetstore/setup A javapetstore/setup/setup.xml A javapetstore/setup/sql A javapetstore/setup/sql/javadb ... Updating your files in Subversion is also very similar to doing it in CVS, as shown here: Listing 8. Updates, SVN style $ svn update U javapetstore/main/java/src/UpdatedClass.java D javapetstore/main/java/src/DeletedClass.java A javapetstore/main/java/src/AddedClass.java G javapetstore/main/java/src/MergedClass.java C javapetstore/main/java/src/ConflictingClass.java ... Updated to revision 10. When Subversion updates your local files, it gives you a summary of the modifications it has performed. All the files affected by changes in the repository are listed, each with a code indicating the type of modification: “U” for Update, “D” for Deleted, “A” for Added, “G” for successfully merGed, and “C” for Conflicting.Conflicts are handled similarly in Subversion and CVS, though Subversion does it in a slightly more readable format:Listing 9. Output of a failed merge <<<<<<< .mine result = useMyFunction(); ======= result = useBertsFunction(); >>>>>>> .r21 Subversion will not let you commit until you confirm that you have resolved the conflict, using the svn resolved command: $ svn resolved javapetstore/main/java/src/ConflictingClass.java You can also add, remove, or rename files and directories using fairly intuitive commands such as svn add, svn copy, svn delete, and svn move.Finally, you commit your changes using svn commit:Listing 10. Committing changes in SVN $ svn commit -m "These are my changes" Adding LocallyAddedFile.java Deleting LocallyDeletedFile.java Sending ModifiedFile.java Transmitting file data .. Committed revision 11. Tagging, branching, and mergingIn Subversion, you tag a revision simply by copying a particular revision (or the latest revision on the trunk) into the tags directory, as shown here: $ svn copy -m "Tagging Release 1.0" http://svn.mycompany.com/trunk http://svn.mycompany.com/tags/release-1.0 Branching is similar, though you may prefer to create a branch based on your local working copy: $ svn copy -m "Creating new alpha development branch" . http://svn.mycompany.com/branches/release-1.1-alpha Now, to switch to this branch, you can use the svn switch command: $ svn switch http://svn.mycompany.com/branches/release-1.1-alpha Finally, you can merge your changes back into the main trunk using svn merge. Merging is one of the less simple aspects of Subversion. To merge back the changes you’ve made in your new branch, you first need to find out what has been changed in the main trunk since you branched. You can do this using the svn log command with the --stop-on-copy option (to ensure that the log stops at the creation of the branch):Listing 11. Change log for a branch$ svn log http://svn.mycompany.com/branches/release-1.1-alpha --stop-on-copy r54 | john | 2007-07-27 22:00:38 +1200 (Fri, 27 Jul 2007) | 1 line ------------------------------------------------------------------------ r15 | john | 2007-06-03 22:00:31 +1200 (Tue, 03 Jul 2007) | 1 line . . . r11 | john | 2007-06-03 21:59:08 +1200 (Tue, 03 Jul 2007) | 1 line This means that the changes in the branch spanned revisions r11 to r54. So, to merge these changes back into the main trunk, you could switch back to the trunk and run the svn merge command:Listing 12. Merge ’em (note the comment) $ svn switch file:///data/svn/dev-repos/javalamp/trunk $ svn merge -r 11:54 http://svn.mycompany.com/branches/release-1.1-alpha ... $ svn commit -m "Merged changes from branch release-1.1-alpha into trunk" It is important to comment the commits when merging, as Subversion does not keep track of branching and merging explicitly.Subversion in summaryOverall, Subversion is a well-designed and well-built version control system, with a host of advanced features, good IDE support, good documentation, and wide community support. Indeed, Subversion is well on the way to fulfilling its mission of replacing CVS as the standard in open source version control systems. On the downside, Subversion doesn’t make it eas to keep track of branches and merges. The copy-based Subversion tagging mechanism is certainly fast, but it lacks the intuitive nature of a command like svn tag.New ideas in version control: Distributed SCMThe next two version control systems we’ll look at are very different from the first two in their design and philosophy. Whereas both CVS and Subversion are based on the idea of a central repository (though Subversion supports read-only mirrors), Bazaar and Mercurial are based on a distributed philosophy, with no central server. The lack of central server is both the main selling point and the primary weakness of distributed version control systems.Instead of having a central repository, each developer using Mercurial or Bazaar has a complete copy of the repository on his local machine. If a developer is working on several branches, he will have several complete copies of the repository. This removes the reliance on a central server, and potentially makes the system more robust. However, developers need to have a good idea of where to get (and/or send) code changes. For larger projects, and over time, the distributed model can have obvious implications in terms of disk space and performance.Meet the new kid, MercurialMercurial is newer open source version control system based on the distributed model. In Mercurial, as in Subversion or CVS, developers work on a local working directory. However, unlike centralized solutions, Mercurial also stores a copy of the entire project history on each developer’s machine. In this way, developers can work in parallel, even without a network connection.Like Subversion, and unlike CVS, Mercurial uses the notion of change sets. Each revision is a snapshot of the project at a given point in time. When you commit your changes, you create a new revision. Like Subversion, Mercurial naturally benefits from fast tags, good support for binary files, and the other advantages related to the use of change sets.Unlike Subversion, however, when you commit changes in Mercurial, you only create a new revision in your local repository (which, given Mercurial is based a distributed model, is considered to be just as good a repository as anyone else’s). Let’s take a minute to see how this works.Setting up your own Mercurial repositoryThe first thing you do when starting a project in Mercurial is to “clone” your own local copy of the project. Not surprisingly for a distributed version control system, you can access a Mercurial repository via HTTP. In Listing 13, I have created a copy of the Mercurial project itself.Listing 13. Cloning a local copy of the Mercurial repository $ hg clone http://www.selenic.com/repo/hg destination directory: hg destination directory: hg requesting all changes adding changesets adding manifests adding file changes added 5027 changesets with 9501 changes to 665 files 583 files updated, 0 files merged, 0 files removed, 0 files unresolved Once you’ve obtained a local copy, modifying existing files and adding new ones is intuitive, using commands such as hg add, hg remove and hg rename. The hg status command, like the equivalent Subversion and CVS commands, lets you see at a glance what has been modified in your project files, as compared to your local repository copy.Listing 14. Familiar operations done in Mercurial $ hg add LocallyAddedFile.java $ hg status M LocallyModifiedFile.java A LocallyAddedFile.java Likewise, you submit changes to your local copy of the repository using the hg commit command, as shown here: $ hg commit -m "Some minor changes" No username found, using 'wakaleo@taronga' instead Push, pull, propagateNote that the hg commit command updates your local repository copy. Because there is no central server to update, you alone will now have an up-to-date repository. This is the major difference between a distributed version control system and a centralized system like CVS or Subversion.To update another repository, you need to propagate your changes onto this repository using the hg push command. Alternatively, another developer could fetch your changes into his or her own local repository copy using the hg pull command. For example, suppose Jill has made some changes that you need to integrate into your source code. To do this, you would “pull” her changes from her machine, like so: $ hg pull http://jill@jillsmachine Merging and branchingOnce you have fetched the changes from another repository, you can merge them into your own repository using the hg merge command. After the merge, you need to commit the merged code to your local repository, as follows: $ hg merge $ hg commit As with any merging, conflicts can arise. When conflicts do happen, Mercurial makes no attempt to merge the two files (unlike Subversion or CVS). Instead, it indicates the conflicting files and leaves it up to you to choose your favorite graphical merging tool to do the job.If you don’t specify where you are pulling your changes from, Mercurial will assume you want to get them from the original repository that you used to clone your local copy. In this case, the original repository acts a bit like a central server. This also applies for the hg push command, as shown here:Listing 15. Pushing changes into the original repository $ hg push *pushing to http://buildserver.mycompany.com/mercurial/repo/myproject searching for changes adding changesets adding manifests adding file changes added 2 changesets with 3 changes to 2 files Branching is handled simply by cloning a new copy of your local repository. Tags are well-implemented: in fact, they are simply references to a particular change set, which you can create using the hg tag command.Listing 16. Tagging and branching $ tag "release candidate 1" $ hg tags tip 2:87726d51f171 release candidate 1 1:1d05b948ba76 Mercurial is a young tool with some refreshing new features, such as simple change-set tagging. Like other distributed version control tools, its user base is smaller than that of a conventional tool like CVS or Subversion. IDE support for Mercurial is also more limited than for either CVS or Subversion, though the Mercurial Eclipse plugin provides some basic IDE integration.Who needs the cathedral when you’ve got Bazaar?Bazaar is recently somewhat famous for being the version control system used by the Ubuntu Linux distribution. Like Mercurial, Bazaar uses a distributed model based on change sets and placing a local copy of the repository on each development machine. Now let’s consider some of the ways Bazaar differs from Mercurial.The first thing you would typically do is identify yourself, so that Bazaar records your name correctly in the log files. I’ve identified myself below. $ bzr whoami "John <john@mycompany.com>" wakaleo@taronga:~/bazaar$ bzr whoami John <john@mycompany.com> If you want to start working on a new project, the next step is to create a new branch of the project on your local machine, using the bzr branch command. This is similar to Mercurial’s “clone” operation. Like Mercurial and SVN, Bazaar is accessible via HTTP. $ bzr branch http://buildserver.mycompany.com/bazaar/myproject--head/ Branched 24 revision(s). This will create a new copy of a particular branch (in this case, the head, or main development branch). You can then work on this copy to your heart’s content.There’s nothing ‘bzr’ about these commandsWhen it comes time to commit your changes, the commands are relatively simple. You can add new files to the local repository, or rename existing ones, using commands like bzr add and bzr mv. The bzr add command deserves an extra mention, because of the extreme simplicity of its use. If you run bzr add with no parameters, it will automatically add all files and directories that are not already in the repository, with the exception of any file patterns you have told Bazaar to ignore (using the bzr ignore command). If you’ve ever struggled with adding files in CVS and Subversion, this command is a breath of fresh air:Listing 17. Adding multiple files with Bazaar $ bzr add added LICENCE.txt added src/NewClass.java added README.txt added test added test/TestClass.java Commits are done using the bzr commit command.Listing 18. Commits are also pretty easy bzr commit -m "Setup new project" bzr commit -m "Setup new project" added LICENCE.txt added README.txt added src added src/NewClass.java added test added test/TestClass.java Committed revision 1. Another nice feature is the way Bazaar handles file deletion. Bazaar automatically detects deleted files, so you have no need of an explicit “remove” command.Listing 19. Bazaar records a deleted file $ rm RedundantClass.java $ bzr commit -m "Removed unnecessary file" missing RedundantClass.java deleted RedundantClass.java Committed revision 2. What’s more, if you make a mistake Bazaar lets you easily roll back your changes using the very convenient bzr uncommit command.Listing 20. Sometimes you just need to uncommit $ bzr uncommit 3 John 2007-08-01 Updated LICENCE text. The above revision(s) will be removed. Are you sure [y/N]? y Pushing and pulling in a distributed networkSo far, your commits have only gone to your local copy of the repository. At some point, you may want to share all your changes with other members of your team. To do this, you use the bzr push command. The hitch is, you need to know with whom you want to share your changes, and where to put them to ensure that everyone who needs to can obtain your latest and greatest code. In theory, you could update each developer’s machine individually. In practice, however, you often do have a central server where developers go to fetch the latest updates.Here’s a sample command to update the code on a central server: $ bzr push http://buildserver.mycompany.com/bazaar/myproject--head All changes applied successfully. Pushed up to revision 2. Of course, when you update the repository, you may run into conflicts with other files. Your first indication of a potential conflict should occur when you push your files to a remote repository: Bazaar will immediately indicate any potential conflicts. bzr push http://buildserver.mycompany.com/bazaar/myproject--head bzr: ERROR: These branches have diverged. Try using "merge" and then "push". Automatic mergingLike CVS and Subversion, and unlike Mercurial, Bazaar supports automatic file merging. The merge algorithm used by Bazaar is fairly robust, though conflicts are still possible. When conflicts do occur, Bazaar uses a similar approach to Subversion to resolve them. Here’s how Bazaar indicates a conflict when I attempt to merge a local repository with a remote one:Listing 21. Bazaar reports a conflict bzr merge http://buildserver.mycompany.com/bazaar/myproject--head M* LICENCE.txt * README.txt * src/NewClass.java * test/TestClass.java Text conflict in LICENCE.txt 1 conflicts encountered. Conflicts are indicated within the file, too, in a format similar to the one used by Subversion:Listing 22. Merge conflicts in Bazaar $ more LICENCE.txt <<<<<<< TREE This is a propriatary license. My lawyer says it's best. ======= Open source rules! This license is GPL. >>>>>>> MERGE-SOURCE Once I’ve fixed the conflict, I inform Bazaar of the fix using the bzr resolve command: $ bzr resolve LICENCE.txt I then need to commit the changes locally, and push them to the remote server.Listing 23. Commit and push $ bzr commit -m "Merged updates" modified LICENCE.txt modified README.txt modified src/NewClass.java modified test/TestClass.java Committed revision 4. $ bzr push http://buildserver.mycompany.com/bazaar/myproject--head Pushed up to revision 4 Tags and branchesBazaar handles branches and tags much the same way Mercurial does, although tags are a relatively recent feature in Bazaar. You create a new branch simply by using the bzr branch command shown above. Tags are managed using the bzr tag and bzr tags commands, as shown here:Listing 24. Managing tags in Bazaar $ bzr tag release-1.0 Created tag release-1.0. $ bzr tags release-1.0 john@mycompany.com-20070801104450-h5xcg35tyy3xxo19 Bazaar is a rich, intuitive version control tool. It is easy to learn and well documented, and has been adopted for some high-profile open source projects such as the Ubuntu linux distribution. On the downside, like Mercurial, IDE support for Bazaar is limited: to date, only an alpha-quality plugin exists for Eclipse.In conclusionIn this article I’ve presented a picture of the feature sets of four prominent open source version control systems. The first system I discussed was CVS. While a good tool in its time, and still suitable for many projects, CVS lacks support for binary file formats and atomic commits, and its slow tagging and branching functions are the bane of developers on larger projects. Subversion, the popular heir to CVS, is better adapted for the needs of most modern enterprise Java development projects. Both CVS and SVN feature excellent IDE support.Bazaar and Mercurial are newer systems that are representative of the distributed approach to version control. Distributed SCM is interesting and offers some practical advantages over centralized management. It could also be argued that the distributed tools offer a more advanced command set. On the downside, the distributed tools lack the user base of CVS and Subversion, and both also lack the quality IDE support that is commonplace for CVS and Subversion.Both Bazaar and Mercurial are excellent, innovative tools, with flexible, well-thought-out features. Of the two, Bazaar is arguably easier to use. Bazaar also can be used with a central repository, which allows users to combine the best of both worlds.See the Resources section to learn more about version control systems and methods.John Ferguson Smart has been involved in the IT industry since 1991, and in Java enterprise development since 1999. His specialties are Java EE architecture and development and IT project management, including offshore project management. He has a wide experience in open source Java technologies. He has worked on many large-scale JEE projects for government and business in both hemispheres, involving international and offshore teams, and also writes technical articles in the JEE field. His technical blog can be found at http://www.jroller.com/page/wakaleo. Build AutomationData ManagementJavaSoftware DevelopmentOpen SourceTechnology Industry