Pages

Wednesday, December 14, 2011

Subversion to Mercurial Migration: Using --splicemap to Map Branches and Merges

I am in the process of migrating all of my existing code projects to Mercurial from Subversion. However, the process has some snags associated with it. The biggest snag is that Mercurial does not understand the branching and merging process which is common in most Subversion repositories.  If you convert a repository from Subversion to Mercurial the timeline indicates the branch, but does not associate it with the parent (default head). This results in "floating" heads (branches). One blogger I found called it a multi-headed Hydra.

Floating Heads (Branches)

What we really want is to show consistency, and progression. We want to show the branches and merges that are stored Subversion in Mercurial. We don't want to lose that vital historical information.

So we now know what the problem is, but how do we fix it. It turns out that the convert extension method has a very poorly (read not useful at all) documented switch called splicemap. This allows us to map specific revisions in parent-child relationships.

In the Rock Hymas blog, they give an example of the format for our splicemap for Subversion. It looks like the following:
svn:<uuid>/path/to/module@revnum
However, he ends short of what to do with this information, or how to obtain it. The article is good on explanation of the issue, but not on how to solve it. I will detail a solution and show you how I did it. I will also show how to use a splicemap "so that others may live"... oh wait that is the US Air Force Pararescue motto. I will show a working example to make a point.

Process

The first thing we will need is the UUID from Subversion. This can be obtained using the svnlook command.
apple1:~ root# svnlook uuid /usr/local/svnhome/
dbc3d074-2bd0-48a6-aa6f-e69526dc1c92
The UUID is absolutely vital. It will be different for every repository.

Next, we need a log of the activity for the project we are interested in mapping. We will use the svn log -v command to get the details. The results will look something like this.  I have shortened my output to just a couple of relevant versions which we will need.

------------------------------------------------------------------------
r417 | jyeary | 2011-12-11 06:28:21 -0500 (Sun, 11 Dec 2011) | 1 line
Changed paths:
   M /MailService/trunk/MailService/build.xml
   M /MailService/trunk/MailService/nbproject/build-impl.xml
   M /MailService/trunk/MailService/nbproject/genfiles.properties
   A /MailService/trunk/MailService/nbproject/jaxws-build.xml
   M /MailService/trunk/MailService/nbproject/project.properties 
  
Merged 3.0 tag to trunk, and updated NetBeans project files. 
------------------------------------------------------------------------
r137 | jyeary | 2008-09-05 19:15:25 -0400 (Fri, 05 Sep 2008) | 1 line
Changed paths:
   M /MailService/branches/3.0-DEV/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/MailServiceBean.java

Updated properties.
------------------------------------------------------------------------
r128 | jyeary | 2008-09-02 17:51:49 -0400 (Tue, 02 Sep 2008) | 1 line
Changed paths:
   M /MailService/trunk/MailService
   M /MailService/trunk/MailService/nbproject/project.properties
   M /MailService/trunk/MailService/src/conf/sun-ejb-jar.xml
   D /MailService/trunk/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/MailService.java
   M /MailService/trunk/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/MailServiceBean.java
   D /MailService/trunk/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/MailServiceRemote.java
   A /MailService/trunk/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/local (from /MailService/branches/2.0-DEV/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/local:124)
   R /MailService/trunk/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/local/MailServiceLocal.java (from /MailService/branches/2.0-DEV/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/local/MailServiceLocal.java:124)
   A /MailService/trunk/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/remote (from /MailService/branches/2.0-DEV/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/remote:124)
   R /MailService/trunk/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/remote/MailServiceRemote.java (from /MailService/branches/2.0-DEV/MailService/src/java/com/bluelotussoftware/mail/ee/ssb/remote/MailServiceRemote.java:124)

merged 2.0 changes into trunk.
------------------------------------------------------------------------

Next we determine how to splice it together. We want to ensure that the parents, and children match up.  The file format is: child parent with a space between the child and parent. We may also provide an additional parent which is separated by a comma such as child parent1,parent2

So the first splice in the splicemap for the 2.0-DEV branch looks like this:

svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/branches/2.0-DEV@95 svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@57

Note: I am splicing the branch to the trunk (parent).

Using the hg convert --datesort --splicemap splicemap1 http://10.0.1.2/svn/MailService resulted in the following output:

assuming destination MailService-hg
initializing destination MailService-hg repository
svn: cannot probe remote repository, assume it could be a subversion repository. Use --source-type if you know better.
scanning source...
sorting...
converting...
21 creating structure
20 Moving project out of MailServiceApplication
19 Fixed javadoc
18 [Netbeans SVN client generated message: create a new folder for the copy]: '
spliced in ['svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@57'] as parents of svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/branches/2.0-DEV@95
17 2.0 development branch
16 1. Updated version numbers.
15 Added new sendMessage() method that allows for different MIME types.
14 1.Added new MimeMessage format to @Remote
13 1.Added new MimeMessage format to @Local
12 1. Added new MimeMessage format
11 Updated project properties
10 1. Created a new local package
9 1. Updated Javadocs
8 Updated project properties
7 merged 2.0 changes into trunk.
6 Adding new development branch
5 Adding trunk to 3.0 Development branch
4 Removed @Local interface implementation from bean.
3 Removed @Local interface.
2 Removed directory.
1 Updated properties.
0 Merged 3.0 tag to trunk, and updated NetBeans project files.
updating tags

More importantly, the result is what we are looking for. See the image below.

Branch
Alright, that solved the branching problem, but the more difficult issue is the merge. I was banging my head on my desk when I came across this Nabble post by Bruce Frederiksen which gave me the clue I needed to merge the branch back to the default head.

We need to tell Mercurial what the parent branches are for the merge from the perspective of the repository. In this case we want the revision at 57 as one parent from the branch above, and the other to be the revision we merge at on the default head. In this case revision 123. We also need to reverse the order (remember what I said about perspective... thanks Bruce). Our new splice looks like:

svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/branches/2.0-DEV@95 svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@57
svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@127 svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@57,\
svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/branches/2.0-DEV@123

Note: I am splicing the trunk@127 to the trunk@57 and branch@123. This is the trick.

Note: The splices are wrapped to fit on the page, the actual file requires each complete splice to be on a new line.

The result when we run the hg convert command again results in merging  the branch back to the default head.

Branch-Merge
Finally, I make the remaining splices to complete the mapping which look like:

svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/branches/2.0-DEV@95 svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@57
svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@127 svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@57,\
svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/branches/2.0-DEV@123
svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/branches/3.0-DEV@129 svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@128
svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@417 svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/trunk@128,\
svn:dbc3d074-2bd0-48a6-aa6f-e69526dc1c92/MailService/branches/3.0-DEV@137

Note: The splices are wrapped to fit on the page, the actual file requires each complete splice to be on a new line.

This results in the final completed completed product.

Completed

Conclusion

I hope that this explains how to effectively use a splicemap to branch and merge your Subversion repository into Mercurial. I hope that this saves some other unfortunate developers from trying to figure out a really cool, but poorly documented feature of the convert extension.

No comments:

Post a Comment