Workflow to use Subversion and Mercurial version control side by side.
Distributed source code management (DSCM) is very popular these days and might take over the world but the current reality is most companies still cling to centralized source control. Most often you will find Subversion (svn) or for the unlucky even CVS.
I won’t reiterate the advantages of distributed vs. centralized version control but if you are interested watch this video of Linus Torvalds trashing SVN.
After going through the five stages of grief lets start with acceptance. Here is a list of the stuff that makes centralized version control a bit painful for me.
* All branches are public * All commits are public * History requires connection * Switching branches is slow * Complete checkout with branches and tags unnecessary big
With that list in mind lets leverage the flexibility of DSCM to minimize those pain points.
* Separation of local and remote version control * Complete offline history with branches and tags * Synchronization with central repository * Push to central repository using native client
I want to live two version control lives. Central repository for working with team members and representing the source of truth plus a rouge local version control regime where I can experiment, branch, fix, delete without affecting other team members.
Subversion and Mercurial
Mercurial offers one time svn conversion out of the box but as Subversion will stay my source of truth I use hgsubversion as a svn integration layer with push and pull support. I don’t use the hgsubversion push functionality as I don’t want to risk leaking Mercurial branches or other meta data to svn but you could easily do so and avoid using svn all together.
The workflow itself looks like the normal DSCM flow of pull, work, push but each action is taking place in its own directory and repository clone.
The pull directory is a staging directory for using hgsubversion to pull changes form svn into an initial hg repository.
This hg repository keeps an exact copy of svn and is the source of truth. All other repositories are clones from pull and sync the incoming svn changes from here.
Work is initially a clone of pull but completely separate. Its focus is purely on introducing changes, fixing bugs and working with hg. Here all features of Mercurial can be used to track work like feature branches, rebasing, many small commits or whatever your style is.
Push is the final staging area for pushing changes back to svn.
Simply put push contains real svn checkouts and a clone of work in the same directory.
To avoid having the complete svn tree with all tags and branches on disk I only checkout specific svn branches on demand. I clone my work repository into those checkouts.
Updating to the same branch in svn and hg should result in the same content without any conflicts.
To introduce changes done in work I just update to my feature branch and override all files that changed. Now svn sees the changes and can be used to commit the changes to the central svn repository.
After I covered the requirements and gave an overview on how it works here comes the complete flow shown on a contrived rubbish example.
Init directory structure
Starting with the initial directory structure.
Import svn project
You use the usual hg notation for clone as it will automatically fall back to svn.
Quick and easy
This assumes that you use the normal svn branches/tags/trunk layout. There are some parameters to map non-standard layouts but I never used them.
My preferred manual approach
For password protected svns I prefer to set up the hg repository manually to provide the svn path and user + password before starting the clone.
This will pull the complete history and branch/tag structure of the svn repository. This will take some time, depending on your svn size. I had cases that took several hours to complete.
This is a one-time effort and works fast afterwards.
Do some work
Ok let’s checkout trunk, create a feature branch and add orm support.
Before pushing to svn we need to checkout the branch we are interested. So I checkout trunk, clone my work directory that contains the feature branch.
As hg won’t clone into a directory that is not empty I clone it first to a temp directory and then just move the .hg directory into the svn checkout.
Push to svn
To finally push the changes to svn we update to the feature branch and replace all files. Using the svn client we can then push the changes to svn.
Pull changes from svn and close feature branch
Now we have come full circle and have our changes in svn and can pull them back in from pull to work etc. To tidy up I am also closing the feature branch as it is not necessary anymore.
This approach might seem like overkill but having the security of many commits and easy revert without sharing all those mini steps and potential conflicts with the team is liberating.