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.
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.
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.
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.