Mercurial Thoughts

Git won. Nobody doubts that. The secret was Github; if it had been “hghub”, Mercurial would have won; git took a long time to get as good as Mercurial, and the sheer weight of Linux kernel developers alone wouldn’t have done it. But Github was an amazing collaborative tool, and it only supported git… and so git won.

There are a few of us still using Mercurial, though, because Mercurial is objectively overall better. Despite this, I increasingly find myself thinking about ditching it completely for git, because the couple of things it does worse, it does much, much worse.

One of those things is shallow clones. Mercurial can’t do them, not without patching the server, which is a non-starter for people who want to collaborate with servers they have no control over. And, frankly, when I want to shallow clone, it’s invariably with a server I have no control over. There are a couple of cases when shallow clones are really useful: one, when you’re only pulling the sources to build them, and have no intention of ever looking at the history. This is the Arch AUR scenario: the entire history has to be cloned just to build the project. This includes those awkward 20MB test data binaries the author accidentally checked in way back in rev 5 and didn’t notice until rev 50, and since Mercurial’s history is immutable, they can’t be pruned and every user forever will be forced to download hundreds of megabytes just to build a project.

The second case for shallow clones is for submitting quick patches. Say I want to submit a patch to correct some misspellings in a README, or maybe I want to contribute a translation. I have to clone the entire project history to make a patch. Mercurial’s lack of shallow clones is a frustrating omission.

The thing which will eventually cause me to ditch Mercurial, though, is that it’s written in Python. Mercurial, like many projects, suffered greatly from the Python 2 -> Python 3 migration. It took literally years for the Mercurial project to come to terms with the changes, and then years more for all of the most important extensions to cross over with it (hg-git). Years… years of limbo, with commands breaking, distractions and diversions to fix or update extensions, sometimes having to entirely disable frequently used extensions because they didn’t match Python versions… years of chaos – it wasn’t a good look for such a critical tool as a VCS, and I have no doubt many users abandoned Mercurial in that time.

But what’s getting me currently is the speed, or the lack of it. The performance penalties of the implementation language are increasingly starting to show.

For me, the performance started being an issue because of a shell prompt. My prompt isn’t particularly fancy, but it does show three things: the current ZSH command index; $PWD; and the branch and dirtiness of the repository I’m currently in. This is done with a little prompt function that calls hg stat (a similar function performs the git equivalent in git repos). This common function is incredibly (bafflingly?) slow. Here is an example: I’m comparing two projects and looking at the relative sizes and speed of commands on the repos:

VCS # of files total LOC # revisions in history stat log
hg 41 4,639 127 196ms 237ms
git 245 62,443 863 9ms 10ms

Mind you, I had to run ‘git stat && git tag && git branch’ to get it to register at all with hyperfine; git status alone took less than 5ms.

You wouldn’t think performance would be a huge differentiator in a VCS, and you could even argue that where it really counts – in the speed of network operations – Mercurial still beats git. But when a user can’t have a simple convenience markup on their shell prompt because the tool is too slow, then performance does matter.

Mind you, Mercurial does have a solution for the performance issue: you’re supposed to install another tool that monitors filesystem changes and “helps” mercurial detect deltas. Only, this tool is watchman, which was written by Facebook, and it refuses to run unless it has a higher priority than the rest of your userspace. Thanks, but no thanks.

Github is still git’s killer feature, although now it’s owned by Microsoft it’s predictably slowly getting worse – most recently, by exposing proprietary code from their paying customers’ private repositories. For now, Sourcehut supports Mercurial very well, and it’s quite a refreshing experience after coming from Github’s Javascript-laden interface. Git itself is still riddled with obscure syntax and foot-guns – foot-guns which are usually inevitably necessary in any long-running project. But it’s not slow, and that, ultimately, may be what converts me.