Using Mercurial with CodePlex and GitHub

For the last few months I've been using git exclusively for source control. The learning curve was quite steep, but after a few weeks I was happily pushing, pulling and rebasing without a .svn folder in sight.

Recently, following the CodePlex announcement, I thought it'd also be a good idea to learn to use Mercurial.

Differences between Git and Mercurial

Coming to mercurial with some git knowledge was quite helpful - mercurial (like git) is a distributed source control system so many of the same concepts apply to both tools. The main difference is often in terminology and that git tends to expose more concepts to the end user. There's also a difference in tooling (more on that later).

Having played with mercurial for a bit, here are some observations:

Git's branches seem more flexible

With git, I can easily create a local branch, write some spike code and then discard the branch when I'm done. Alternatively, I can push a branch up to the remote repository when I want to share it with others. Mercurial branches are always pushed up to the remote repository and cannot be removed (although they can be marked as "inactive"). To achieve a similar functionality to git's local-only short term branches you need to use a bookmark instead.

Setting up an hg server on Windows is easier

Setting up an ssh server on windows in order to host git is....somewhat painful. My colleage Mark Embling configured our git server at work and detailed the process in this blog post. Setting up a mercurial server on windows is slightly easier - it involves hosting the hgwebdir plugin in IIS (or another webserver).

Implicit rename tracking

Git does implicit rename/copy tracking, while this is explicit with mercurial. This will take some getting used to...

Update 19 Feb Mercurial does actually support implicit renames, it just isn't turned on by default. To enable it, you can pass the --similarity argument to hg addremove.

The Index

Git exposes the concept of the "index" or "staging area" where you add or remove files prior to a commit. In Mercurial, this is not exposed to the end user. In my opinion, Mercurial's approach is better here - I don't think I've ever run into a situation where I *needed* to see git's index.

Windows Tooling

Git support on windows is reasonably smooth these days, but isn't as smooth as mercurial. By far the easiest way to run git on windows is by using msysgit which is built around MinGW (a GNU environment for windows) while Mercurial being written in python means is cross platform by its very nature.

The msysgit installer comes with a simple git gui and there is also the somewhat incomplete tortoisegit however, I never really used these as I'm a big fan of using the command line.

That being said, I really like TortoiseHg which is an all-in-one installer for Mercurial, Python and Windows GUI tools. Perhaps ironically, I don't actually use TortoiseHg's Windows Explorer integration (I've never been very keen on right-click context menus) but instead use TortoiseHg's command line support to open the appropriate gui tools directly from my console window. For example, if I type the following command into my console:

hgtk log

...this will bring up TortoiseGit's log viewer for the current directory (which I find a much more useful view than the normal "hg log" output)

I'm sure I'll encounter more differences in time, but these were the ones that were immediately noticable.

Using Mercurial to push to GitHub and CodePlex

A few weeks before CodePlex unveiled Mercurial support, I decided to move the FluentValidation source code to github to get away from the horror that is TFS+svnbridge. Now that CodePlex does support Mercurial I considered moving the source back again, but I don't want to lose the FluentValidation repository on github (it's gathered a nice little collection of followers). This is where hg-git comes in.

Hg-git is a plugin for mercurial that allows you to use mercurial push and pull from git repositories. This means I can work with hg locally and push up to both CodePlex and GitHub when I'm done.

If you already have TortoiseHg installed then this is a very simple process (as it already comes with the necesary Python plugins). First, you clone the hg-git plugin locally:

cd c:projects
hg clone http://bitbucket.org/durin42/hg-git/

Next, you enable the extesion in your Mercurial.ini under the "extensions" section:

[extensions]
hggit = C:projectshg-githggit
bookmarks =

(note you also need the bookmarks extension)

At this point, you can now clone a git repository using hg. In this case, I cloned the FluentValidation git repository:

cd c:projects
hg clone git+ssh://git@github.com/JeremySkinner/FluentValidation.git

Note that I'm using the private ssh url.

At this point I can now add a new "path" (equivalent of a git remote) to the hgrc file inside the .hg directory. The default will point to github, and I can add a new path for codeplex:

[paths]
default = git+ssh://git@github.com/JeremySkinner/FluentValidation.git
codeplex = https://hg01.codeplex.com/FluentValidation

At this point, typing "hg push codeplex" will push my repository up to the mercurial repository on codeplex, while a normal "hg push" would push up to github. Sweet.

Update: 21 Feb 2010 I’ve had some serious problems getting this approach to work reliably with two-way syncing. For now, I’ve decided to use CodePlex as a read-only mirror pulling changes from github.