Software is complex. You wouldn’t believe how complex it is. You might think a skyscraper is a complex system, but if buildings got built like software, you would frequently run into fractal cathedrals filled with basketball halls, space ports and zero gravity hair styling salons, reaching into higher orbit and standing upside down on one of their many towers.
Because software is complex, people tend to reduce focus to what they think is most important and polish it as well as they can. However, every once in a while, one stumbles over something which can only be called a diamond because from whichever point of view you look at it, it always looks perfect. One such system is Mercurial, an SCM system.
To put things into context, it is worth pointing out at this point that SCM software tackles a number of difficult tasks: sensible file comparison, efficient storage and retrieval of a large number of versions of code, access control and extreme performance, among many others.
To begin with, Mercurial has a simple and concise command set. A dozen or so commands are all that is needed to get everyday tasks done: init, clone, push, pull, incoming, outgoing, diff, [g]log, merge, rollback, resolve. That’s about it. The learning curve appears steeper than with Subversion or CVS because the comparison is frequently made with a few demonstrably broken assumptions. The first is that it doesn’t matter that centralized SCMs don’t come close to the kind of flexibility Mercurial offers so it is like complaining the Mars rover is more complicated than a skateboard. The second assumption (the one with the serious implications) is that the complex, elaborate and grotesque workaround procedures necessary with CVS or Subversion to get serious work done – don’t exist because their users don’t know them and pretend to do fine without them.
In terms of features, the leaders are Mercurial, Git and possibly Bazaar. While Git boasts its speed, it is unclear if it is faster than Mercurial, but the point is moot: they are really very fast anyway. However, Git can’t seem to shake its reputation for being difficult to work with. A quote I ran into a few times illustrates this better than anything that comes to my mind: “Git’s changed, man! It’s not like it used to be, it’s totally intuitive now! You just gotta learn how it stores the data!” Of the best SCMs, Mercurial is the simplest to use.
One of the most difficult operations with SCM systems is code merging and Mercurial is second to none there. Even taking into account that Subversion 1.5 finally learned to remember what was merged and in which direction (many shops still use older, broken versions), Mercurial can e.g. handle move/rename operations better than Subversion. Subversion requires the user to explicitly tell it what happened to each file which basically makes move/rename detection unusable unless you’re using an IDE with heavyweight integrated Subversion support. Not that it is something you would want to do, but I have performed a merge of branches with a 10k diff in a day and ended up with a working system in the end and have performed larger merges since without jeopardising my sanity.
Mercurial has a core of 20k lines of mostly python code. That might not mean much to many people, but it is the equivalent of building a jet aeroplane weighing about the same as its pilot. That kind of simplicity is what engineers and mathematicians call beautiful. It has a small repository, it is very well documented, works offline for an effectively arbitrary amount of time, has adapters for a number of other SCMs, has a templatable log, instant ad-hoc server, loads of excellent extensions, etc.
Having to use anything else feels like having to leave the Louvre to spend the afternoon in the 3rd grade classroom looking at children’s drawings of trees.
I will end by starting a growing list of little things…
- Subversion whitespace insensitive diff:
svn diff --diff-cmd diff -x -uw; Mercurial equivalent:
hg diff -w
- with Subversion, create revisions 1, 2 and 3, go back to 1, modify and commit and you’ve just overwritten changes introduced with 2 and 3; Mercurial understands that what I’ve done is branched my code
- Subversion doesn’t mind if you make changes to your “tag” because its “tag” is actually just a regular folder
- searching for anything in a mercurial working directory:
grep -r something *; searching for anything in svn:
grep -r something * | grep -v .svn
- with Mercurial, you don’t have to pay attention to avoid packaging .svn folders into your assemblies (e.g .jars)
hg grep xyzsearches for xyz in all versions of all files in the repository. And it takes longer to type than to execute.
svn upjust took several minutes and raised the machine load to 8 doing an big update:
hg pull && hg uptime is usually network-bound and has no noticeable effect on the CPU
svn st: identical to
- setting ignore patterns is ideal: use your editor to add a regex to the .hgignore file and it’s applied to the entire repository: Subversion simulates that by updating subfolder ignore properties, but a subdirectory created later will not have the ignore pattern
Other recommended reading:
- Rock Hymas – Mercurial will make you a better developer