One of the particularly nice things about working with a distributed revision control tool these days is that I can sidestep the choice of winning tool. Thanks to Scott Chacon and Augie Fackler’s excellent hg-git extension, I can use Mercurial and collaborate almost seamlessly with git users. This is exactly what I did when working with Johan on the new I/O manager subsystem in GHC 7, and the experience was generally very smooth.

The only mild annoyance has been that I’d prefer to also not be forced to choose a hosting winner: although bitbucket is pretty good, github is currently far slicker, and has a much larger community of potential collaborators.

I’ve hosted most of my code on bitbucket for quite a while. Until this morning, I had a somewhat awkward way to mirror code to github. I just automated the problem away.

My automation scheme is implemented as a Mercurial hook. Here’s how I’ve enabled it in my $HOME/.hgrc file:

[hooks] post-push = python:/home/bos/share/python/github\_mirror.py:post\_push 

That github_mirror.py hook is very simple. Every time I push, it checks to see if I’m pushing to a bitbucket repository, and if so checks my local repo’s .hg/hgrc file to see if I have a mirror on github. If I do, it pushes to github, too.

from mercurial import commands

def post_push(ui, repo, pats, opts, \*args, \**kwargs):
 dest = pats and pats[0]
 dest = ui.expandpath(dest or 'default-push', dest or 'default')
 if 'bitbucket.org' in dest:
 github = ui.config('paths', 'github')
 if github:
 return commands.push(ui, repo, github, **opts)
 ui.warn('no github mirror!?\n')

How do I tell Mercurial that I have a girhub mirror? In a repo’s .hg/hgrc file, I have something like this (taken from a real repo):

[paths] default = http://bitbucket.org/bos/pcap default-push = ssh://hg@bitbucket.org/bos/pcap github = git+ssh://git@github.com/bos/pcap.git 

The github_mirror.py hook looks for that github key in the paths section of the file, and uses it if present.