Marramgrass

Migrating a Subversion repository to Mercurial.

If the title of this post doesn't mean anything to you, you're pretty safe to skip it.

Like many others, I've been using Subversion for source code management and version control. I have mostly been happy, but over the weekend I'd had enough of some of the foibles by which Subversion shows its age. After playing about with it for a while, I decided to move to Mercurial.

Distributed VCS is all the rage right now. All the cool kids seem to be using Git, but Mercurial appealed to me more. There are other options, as well.

Migrating from Subversion to Mercurial should be easy. Mercurial includes the hg convert extension, which takes your Subversion repository and converts it to Mercurial while maintaining all your branches and tags as well — if you can get it to work. I tried for an afternoon and couldn't get it to fire. (I was working with a remote repository. You may have better luck working locally.)

I decided to try hgsvn, which I installed from MacPorts as py25-hgsvn. It aims to allow you to use Mercurial to manage a repository and then push and pull from a Subversion repository. I didn't take it that far, though if you try it please let me know how it works. I was mainly interested in making the switch completely, which I managed reasonably well.

Before we go through the process, here's one thing to bear in mind: if your Subversion repository contains tags and branches, these will appear in your new mercurial repository as directories containing a bunch more source code, with the whole directory structure making up one big working copy. This makes sense if you think about it, as branching and tagging in Subversion is nothing more than making copies of your files and promising yourself (and your collaborators) that you'll treat them a certain way.

Because of this, I found that this will work best if you select a certain branch (maybe your trunk, maybe not) and convert it only. So this process will work best for you if you're working on your trunk, or only want to bring over one branch with its revision history.

With that in mind, here's what you do. (I'm on Mac OS X, but this should follow for most *nix-type systems. On Windows, it may well be a bit different.)

Set up the conversion using, for example

$ hgimportsvn http://yourrepo.com/trunk/

In this example, the new Mercurial repository will be in a folder called ‘trunk’, so you may want to rename it by

$ mv trunk MyProject

Move into that directory and grab the contents of the repository with

$ cd MyProject
$ hgpullsvn

At this point, you will be able to run this as a Mercurial repository without any trouble. However, there is a little cleanup we can do to make everything neater.

First, because hgsvn is designed to allow Mercurial and Subversion to coexist, but that's not what we want, you can get rid of the .svn cruft and the file that tells Mercurial to ignore that cruft, using

$ find . -name .svn | xargs rm -frv
$ find . -name .hgignore | xargs rm -frv

(By the by, if you're planning to pipe find into rm, especially with the -f switch, it's best to run the find first to check you're only going to delete what you want to, and only then run it with the pipe in place. Man, am I glad I checked it first!)

Second, if you run

$ hg branches

You'll see that your main branch is currently called ‘trunk’ instead of ‘default’ — which is what a new mercurial repository would have. You can correct this by running

$ hg branch default

By now, you'll have made a few changes to the contents of your working copy, so commit them with

$ hg commit -m "Cleaning up after migration to Mercurial"

And that's that. It's easy when you know how.

(I found useful clarification on a little of the cleanup from samhart.com.)