Mercurial

git is the hype-child of the hour, what with github bringing it to the masses in a format everyone loves, Web 2.0! It's a great site, but it's distracting from the distributed revision control system I think deserves the limelight: Mercurial. So here it is, the post all the git-love on Twitter and the Rails blogosphere has forced me to write.

Begin

Got a project already? Jump into its directory and enforce Mercurial rule:

$ cd proj
$ hg init

This creates one directory called .hg to identify it as a repo.

$ hg add *
$ hg st
A index.php
A mainbg.gif
A style.css
$ hg ci -m "Imported old code"
$ hg st

Noticed what's missing? Noise. Takes you back to your Subversion days, huh?

I've found that the easiest branching mechanism, with Mercurial anyway, is to make a copy by cloning the original. The branch is its own repository, so it can in turn be cloned, have changes pushed to it, get changes from other repositories, etc. But I'm getting ahead of myself.

$ cd ..
$ hg clone proj proj-feature
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd proj-feature
$ sed "s/921fff/8822ff/" < style.css > out
$ mv out style.css
$ hg diff
diff -r 31e323fd8346 style.css
--- a/style.css	Sun Mar 30 16:29:53 2008 -0400
+++ b/style.css	Sun Mar 30 16:40:00 2008 -0400
@@ -70,7 +70,7 @@ div#header {
  }

 div#focusbox {
-	background-color: #921fff;
+	background-color: #8822ff;
  margin: 15px 0;
  padding: 7px 0;
  text-align: center;
$ hg ci -m "Fixed a color"

Ship the change back to the original repository.

$ hg push
pushing to /Users/tom/proj
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files

It's not magic; Mercurial just made the assumption that you wanted to push back to where you got the sources originally. It's just a setting in a text file:

$ cat .hg/hgrc
[paths]
default = /Users/tom/proj

(That's the whole repository config.)

After pushing, the changes are floating in the ether in proj. They aren't automatically applied to the files on disk. If there had been no changes in proj since it was cloned to proj-feature, then "merging" the branch back in is simple:

$ cd ../proj
$ hg up
1 files updated, 0 files merged, 0 files removed, 0 files unresolved

But what would have happened had there been changes? Let's rewind to before the push and see.

$ hg rollback
rolling back last transaction
$ hg revert style.css
$ rm style.css.orig
$ sed "s/2004/2008/" < index.php > out
$ mv out index.php
$ hg diff
diff -r 31e323fd8346 index.php
--- a/index.php	Sun Mar 30 16:29:53 2008 -0400
+++ b/index.php	Sun Mar 30 16:55:33 2008 -0400
@@ -106,7 +106,7 @@
  </div>

  <div id="footer">
-		<span>Copyright © 2004</span>
+		<span>Copyright © 2008</span>
  </div>
 </div>
</pre>
$ hg ci -m "Updated the copyright"

Instead of pushing this time, let's pull from the branch. It's the same as pushing, but from the other end.

$ hg pull ../proj-feature
pulling from ../proj-feature
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg heads
changeset:   2:324dc60c0390
tag:         tip
parent:      0:31e323fd8346
user:        Tom Lieber <tom@alltom.com>
date:        Sun Mar 30 16:44:41 2008 -0400
summary:     Fixed a color

changeset:   1:67e41a726fb5
user:        Tom Lieber <tom@alltom.com>
date:        Sun Mar 30 16:57:10 2008 -0400
summary:     Updated the copyright

$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m "Merged in the feature"

Still easy.

Remote Repositories

Everything works the same with repositories on remote servers. As is usual for such tools, the URI is simply overloaded to accommodate:

Mercurial is distributed with two CGI scripts, hgweb.cgi and hgwebdir.cgi, which serve single or multiple Mercurial repositories, respectively. hgweb.cgi works with very little effort; the path to and name of the repository to serve are hard-coded into the script. For even more transient hosting, the hg serve command will start a web server to host the repository in the current directory.

Mercurial is beautiful software to use. It's so lightweight that I use it for everything: web sites, essays, C projects, and so on. I installed it to my home directory on the university's computers. I couldn't recommend it any more highly.