Thursday, May 6, 2010

Running Mercurial with Subversion

On the project I'm currently assigned to, we use Subversion as our version control system. Subversion is a great tool and is certainly a step up from the alternatives that we have used in the past. However, after reading a fair bit about Distributed Version Control systems (hginit), such as Mercurial, I've been wanting to play around with one of these systems in a real project. Code version control is not something that should be changed on a whim, so there's little hope for me to get Mercurial adopted department wide. But, the very nature of Distributed Version Control systems offer a way to utilize the system without forcing it upon others.

Distributed Version control systems offer 2 main benefits. First, they allow a user to keep a local repository of changes without having to pollute the central repository with changes that may break the build or unit tests. For those coding large components that take weeks to finish or those who are doing exploratory coding, checking code into a central repository is not feasible.

Another, less obvious benefit comes from how Distributed systems record revisions and perform merges. Whenever the code is checked into a local or central repository, a diff of the changes between the last revision and the new revision are stored. When a merge is performed, the code can replay the diffs to create a merged file. This will not solve every merge conflict, but it goes along way to make merges less painful.

Thanks to a Python package called hgsvn, I was able to download our project's code from the Subversion repository and place it in a local Mercurial repository in one easy step. The package hgsvn contains 3 scripts. The first, hgimportsvn, takes the URL to the SVN repository and then will download the code from the central into the current directory. After the code has been downloaded, it is then checked into a new Mercurial repository. This last part is done en masse and can cause problems if you have a very large code base and/or a very large file in that code base (as I would have very good reason to know).

If you run into this problem as well, 1 solution to try is to call hgimportsvn on the various sub-folders of the central project. In some instances, this can be made to work, but not in others and I can't find a rhyme or reason behind it.

The second script in the package is hgpullsvn, and it pulls the latest code from Subversion for the current directory and places it into the Mercurial Repository. Each revision in Subversion gets its own corresponding revision in Mercurial, and hgsvn keeps track of what Subversion revisions have been brought over to keep everything in sync. Unfortunately, it seems to overwrite in local changes that have not been committed into Mercurial, so ensure that Mercurial is up-to-date before running this.

The last script is hgpushsvn, and it commits any code you've checked into Mercurial into Subversion. While you can certainly use this tool, I've found it just as easy to use TortoiseHG to check the changes into Mercurial, and then use TortoiseSVN to commit those changes into Subversion when I'm ready.

Using Mercurial locally, Subversion on a central server, and hgsvn to synchronize the two, one can get a large benefit of using a Distributed Version Control System, without forcing the system upon others.

No comments:

Post a Comment