Thoughts on Systems

Emil Sit

Experiences With Mercurial and Git

I have been a big fan of the Mercurial version control system since migrating the Chord project from CVS almost two years ago. Mercurial offers a comfortable command-line experience, good performance and a module based architecture for expansion. Since graduating, I have had to interface with Subversion and Perforce servers at work and used that as an opportunity to learn how to use Git, the other big player in the distributed version control world.

Learning Git can be a bit daunting—concepts like the index, the abstract model of Git repositories as a directed acyclic graph, and commands like git-reset and git-rebase are hard to wrap your head around. Coming from CVS or Subversion, it is easy to think that Git is just weird, much like Lisp macros might confuse the average programmer. However, last year, Ted Ts’o wrote

[…] I see its potential as being greater than hg, and so while it definitely has some ease-of-use and documentation shortcomings, in the long run I think it has “more legs” than hg, […]

Having gotten comfortable with Git, I definitely agree with this statement.

Compared to Mercurial, branching with Git is much easier. When developing features for Chord, I would use Mercurial’s patch queue extension to develop features piece-meal until they were ready to commit. I would edit the series file manually to rearrange commits, in particular to push out small bug-fixes. It is much easier to use topic branches or git-stash to arrange (and re-arrange) commits and do small fixes. Git’s view of branch heads as simply pointers to some commit on a commit graph and its constant tracking of your commit history with reflogs around allows you to develop without fear of losing your work, even when arranging things so that your published history is pretty. In Mercurial, last I checked (around version 0.9.4), branches in a single working tree were still somewhat confusing and hard to use.

Git also has excellent Subversion and Perforce front-ends. With git-svn and git-p4, you can mirror an existing repository (say, the official version control system at the office) into Git, develop using all of Git’s tools, then push changes neatly back into Subversion and Perforce. Mercurial has hgsvn but I haven’t used it and its documentation suggests that it can’t push changes back into Subversion; I don’t know of any Perforce front-ends for Mercurial.

Mercurial makes it extremely easy to serve up a repository, without requiring starting a daemon on any special ports. hg serve is all you need and you can efficiently clone a Mercurial repository over HTTP; Git uses a special protocol that runs over a dedicate port, making it somewhat less firewall friendly. Mercurial also better allows differences between the HEAD branch (aka tip) and your current working directory state—you can push into a repository with a working directory without confusing Mercurial; not so with Git. This means collaboration in Git requires a third copy of the repository for collecting commits (or requires that repositories be updated only by pull).

For most uses, Mercurial and Git are more-or-less interchangeable, especially with the usability improvements in versions 1.5 of Git and later. The most basic commands like status, diff, commit, and log behave very similarly (at first glance). Commands execute quickly, even for large trees. Both systems are very flexible with modules and scripts that bring most features to parity. For myself, having learned how to work with Git, I prefer the power Git offers with fast branches and powerful tools like reflogs and rebase. For the undecided, fortunately there are tools that convert repositories from Git to Mercurial and vice-versa, so other than mental switching costs, there is little to fear in choosing one or the other. I won’t be using Subversion or CVS any more if I can help it.