Importing SVN to Mercurial with complex SVN repository

by Shannon Deminick 2. November 2010 05:14

Here @ TheFARM, we’ve been moving across to Mercurial (on BitBucket) for our code repositories. In many cases our SVN repositories are structured ‘normally’:

  • trunk
  • tags
  • branches

Using the ‘hg convert’ command line, when your SVN repository is structured this way will import your trunk into the Mercurial ‘default’ branch and your branches/tags into named branches. This also imports all history and revisions. From there, you can merge as you wish to structure your Mercurial repository the way that you want.

However, in some cases we have more complicated repositories. An example of this is a structure like the following:

  • trunk
    • DotNet
    • Flash
  • tags
  • branches
    • v1.1-DotNet
    • v1.2-Flash

In the above structure, we’ve actually branched the trunk/DotNet & trunk/Flash folders separately into their own branches. Unfortunately, Mercurial doesn’t operate this way so it doesn’t really understand creating branches from folders. There’s a couple different ways that you can get this from SVN into Mercurial whilst maintaining all of your history…

One way is to run ‘hg convert’ on the entire repository. You’ll end up with 3 branches in Mercurial: default, v1.1-DotNet & v1.2-Flash. The problem is that if you try to merge the named branches into default, you’ll end up with a mess since the branches don’t have the same folder structure as default. To overcome this, you can restructure each named branch to follow the same folder structure as default. To do this, we us the ‘rename’ method on Tortoise Hg. So for instance, if we had this folder structure inside of v1.1-DotNet:

  • BuildFiles
  • MyProject.Web
  • MyProject.Config

So that we can merge this with default we need to restructure this into:

  • DotNet
    • BuildFiles
    • MyProject.Web
    • MyProject.Config

So we just need to right click each folder seperately, and select the rename option from the Tortoise Hg sub menu:

image

Then we prefix the folder name with the new folder location which will the ‘move’ the file:

image

Now that the named branch v1.1-DotNet is in the same folder structure as default, we can perform a merge.

The other way to import a complicated SVN structure to mercurial is to convert individual branches to mercurial repositories one by one. The first thing you’ll need to do is run an ‘hg convert’ on the Trunk of your SVN repository. This will create your new ‘master’ mercurial repository for which will push the other individual mercurial repositories in to. Next, run an ‘hg convert’ on each of your SVN branches. For example: hg convert svn://my.svn.server.local/MyProject/Branches/v1.1-DotNet.

Once you have individual repositories for your branches, we can force push these into your ‘master’ repository. To do a merge of these branches, the above procedure will still need to be followed to ensure your branches have the same folder structure as default. HOWEVER, because we’ve forced pushed changesets into Mercurial, it has no idea how these branches relate to each other (in fact, it gives you warnings about this when you force push). When you try to do a merge, you’ll end up getting conflict warnings for every file that exists in both locations since Mercurial doesn’t know which one is newer/older. This can be a huge pain in the arse, especially if you have tons of files. If we assume that the branch files are the most up to date and we just want to replace the files in default, then there’s a fairly obscure way to do that. In the merge dialog, you’ll need to select the option “internal : other” from the list of Merge tools:

image

This tells Mercurial that for any conflict you want to use the ‘other’ revision (which is your branch revision since you should have default checked out to do the merge).

We’ve had success with both of these options for converting SVN to Mercurial and maintaining our history.

Categories: Source Control

Comments

11/2/2010 6:07:47 AM #

Pingback from topsy.com

Twitter Trackbacks for
        
        FARMCode.org | Importing SVN to Mercurial with complex SVN repository
        [farmcode.org]
        on Topsy.com

topsy.com

6/14/2011 7:13:13 AM #

For the second method (doing a hg convert for each branch), I believe you might want to try to specifying the same destination repository for each call to hg convert.

That way the .hg/shamap file (which keeps track of which svn commit maps to which hg commit) will be re-used and the branching history of the original svn repository might be preserved (assuming you used the svn branch feature originally).

Granted, while doing this worked for me, there was something about the way I specified my parameters so that, apart from creating and overwriting the tags file, my converted changesets kept ending up in named branches rather than the default branch (I think if I wanted to get around that, I could have done the hg convert on the trunk and had a branchmap that renamed the named branch to default, and then on the subsequent calls to hg convert for the branches, they wouldn't need that rename, because the changesets they shared with what was converted into the default branch, won't be re-converted since they were in the shamap file and will still have the default branch as their branch - at least, that's what my limited playing around with hg convert left me believing.  If you have the reverse problem, all the converted branches trying to end up in default, I imagine you could give the calls to hg convert on the branches a branchmap to rename default to their appropriate branch names.  And as I said before, I believe their change-set histories shared with the main/default branch should still be default because they were converted in the first call where the change-sets ended up in the default branch).

My apologies if you've covered this option in a more recent post.  Was just browsing around some umbraco/hg stuff, saw this post, and had my own recent playing arounds with hg convert to solve a similar problem.

Mark United States

6/14/2011 7:16:14 AM #

Oh, and I forgot to say, if you're doing repeated calls to hg convert, you'll probably want to wrap them up in a batch file.  It'll just make the experience of trial and error a lot easier and serves as documentation as to what your hair-brain scheme for converting the repository was.

Granted, that might have been implied already.

Mark United States