Distributed Version Control showdown

To quickly catch up those people why don’t keep up with the latest advances in programming technology, Distributed Version Control Systems (DVCS) are the latest craze, a version control where every working copy is a repository in it’s own right. When I first started learning about DVCS that explanation didn’t quite explain the point of it, so I’ll put it this way: you can commit as often as you want without having to be connected to a server, and everyone has a copy of the data so nothing is lost if the aircon stops working in the server room and the hard disks melt. These are good things :)

There are two major frontrunners in Distributed Versioning: git, lorded over by Linux creator Linus Torvalds to quell his hatred of SVN (and, according to him, give his name to another piece of software); and Mercurial, overseen by Matt Mackal as a way of thumbing it to the devs of the previously free BitKeeper.
Both are free and open source, originate from Linux platforms, and are traditionally command-line tools. Mercurial is the poor bastard that will take over from SVN once we have time to upgrade, while I use git quite a bit for my personal shi…projects, thanks to the pretty cool ProjectLocker.

For this article, I’m going to be comparing command-line hg & TortoiseHg – the Tortoise-branded GUI on top of Mercurial, with command-line git & the Git GUI included with msysgit on Windows. There is a Tortoise GUI for git as well, but to be frank it’s atrocious and I refuse to use it. Which I suppose leads me to the first point to compare: Interface.


On the command-line, both are pretty much the same. They have almost identical commands for day-to-day use (status, log, commit, push, pull, update etc). They both have quite good help on usage of each command. Mercurial maybe gets a slight edge because it only require typing two characters (hg) instead of three (git) before each command.

Graphically, git is a loser. It doesn’t feel particularly fair, because the msysgit GUI is supposed to be a usable fallback, not the preferred interface for git. Without any better options in sight though, I have to pick on it: the interface is clunky, there’s keyboard shortcuts listed in the menu that just don’t work, and the hunk selection is really badly done. This last point wouldn’t be an issue, except for that fact that git has a ‘staging area’ that seems to be mainly for doing this kind of work. More on this later, though. The repository GUI is decent, but doesn’t seem to offer any decent interface for merging files, which is what I would mainly use it for.

The Mercurial GUI is much more intuitive. The commit dialog includes quite a good way to commit individual ‘hunks’ of code instead of a whole file, as well as being somewhat easier than git to add new files/renamed files etc. Not without it’s shortfalls though, there’s no way to check/uncheck multiple files for a commit in a single batch – I have to go through and tick/untick every one. The Branch functionality confused me somewhat too, but once I had the hang of it I found it made sense. The repository GUI is quite good, and includes an interface for merging heads by updating to one head, then right-clicking on the sencond head. Both screens have useful links to the synchronisation GUI for pushing and pulling changes with other repositories.

Result: Git – Slightly burned French Fries floating in a Thickshake, Mercurial – A tasty chicken burger, with occasional gristle and annoyingly small seeds on the bun.

General Usage

I use a lot more features of Mercurial than git on a daily basis, because I work with multiple users in hg, but only by myself on git. So for now, I’ll limit ‘general usage’ to the edit-commit-pull-push cycle. There’s a fundamental difference between git and mercurial when it comes to commits: git has a ‘staging area’ between the working copy and the repository where the commit can be set up, hunks or lines added/removed, and then finally committed from. In theory it seems like a neat idea – in practice it ends up being an additional command to have to type/click whenever I’m adding new files in a commit. If I make any mistakes, git will allow the last commit to be ‘amended’ with any new changes, which is useful for adding or changing files, but not if I’d accidentally added some. Pulling and Pushing to synchronised servers work well, although the need to explicitly set the default branch by editing a text file is a turn-off.
Mercurial has no working queue, and instead commits directly to the repository. It’s quite possible and easy to select which parts of a file to commit in a particular change though, and it keeps me to a single command for everything. Any mistakes can be handled by ‘undoing the last commit’, which then throws all the committed files back into the working directory – effectively emulating git’s behaviour while also making it easy to take files out of the commit. Pulling and Pushing to other repositories is on par with git, but it’s a nice addition to have a GUI for setting this up.

Result: Mercurial – Teriyaki Chicken Sushi with Soy Sauce and Pickled Ginger, Git – Unexpectedly slimy Unagi with a tasty, if brief, Mochi dessert.

Advanced Use

Undoing/redoing multiple changesets, merging unrelated repositories, removing revisions etc. I’ll have to mainly cover this one theoretically, as I’ve only done a little of this. Mercurial comes with a ‘Mercurial Queues’ extension to allow most of this to happen, but it’s not all that intuitive and the GUI for using it is somewhat limited. With Tortoise-Hg it seems to work well for stripping revisions, but more complex work than that requires quite a bit of faffing about.
Git on the other hand has the rebase command. Which I’ve never used. But judging it purely on the forum posts and tutorials I’ve read, it seems to be the better of the two. The fact that someone took the effort to try to recreate the command in a mercurial extension seems to hint at that too.
Result: Git – Three layers of jelly with red beans, Mercurial – Delicious, floury Daifuku.

Branching and Merging

The very point of DVCS (other than not getting in trouble for Friday night Ninja-commits that don’t actually compile) is to give many more ways to deal with and resolve divergent changesets. In other words, branching and merging. I can sum this up with the following sentence: git does it more securely, mercurial does it more easily. As a programmer in a small team, easily is more important than securely for me – programmers calling branches the same name is not much of an issue in a small team. Mercurial also has a feature called named branches that has no equivalent in git – letting users see what branch a changeset was made on at any commit within the set.
Result: Mercurial – Muesli flakes with fresh raisins and strawberry yoghurt, Git – Coco Pops and Milk. And Diabetes.

The Verdict

Overall these are both really useful version control systems, each with their own advantages and disadvantages. For me though, Mercurial is the more delicious of the two: it combines a powerful command-line program with a GUI robust enough that I don’t need to use the command line most of the time.

3 thoughts on “Distributed Version Control showdown

  1. You don’t need to use “git add” then “git commit”; in most cases “git commit -a” would suffice… but in those cases when it does not (e.g. complicated merge resolutions) you would be happy that git has explicit staging area (the index).

    Modern git has “git remote set-head” (sub)command, so you don’t need to edit config file (or use “git config” to edit it) to set up default branch on remote nowadays.

    “git commit –amend” can also be used to remove files or changes to files from a commit; everything depends on preparing staging area (or working area with “git commit –amend -a”). “git rm –cached <file>” or “git checkout HEAD^ — <file>” could help there.

    So called “named branches” in Mercurial are more of a “commit labels”. Forever they mark your revisions.

    See also my answer to “Git and Mercurial – Compare and Contrast” question on Stackoverflow: http://stackoverflow.com/questions/1598759/git-and-mercurial-compare-and-contrast/1599930#1599930

  2. True, but using git commit -a doesn’t pick up any new files that have been added to the repo. git add then git commit is the only technique that will cover both new and changed files.

Leave a Reply

Your email address will not be published. Required fields are marked *