This is a quick "how-to" on how to use Mercurial to work locally with a remote read-only Subversion repository. Many open-source projects now use Subversion, and rather than allow write access to their repository they accept patches in "universal diff" format. This how-to will show you how to set up your own Mercurial repositories to mirror the Subversion repositories, and to generate diffs against the current Subversion revision.
For a lengthier discussion targeted at Mercurial novices, please see my original blog posting "How To Use Mercurial For Local Source Code Management With A Public Subversion Server" at http://www.momentaryfascinations.com/.
1. The basic approach
- Check the tree out from Subversion and in to a Mercurial repository. This branch will always be read-only.
- Clone that tree to a second repository. This is the tree where you do your work.
- When there are updates to the Subversion tree, update your read-only tree and pull the changes into your work tree.
- When it's time to make your patch, diff your work tree to the read-only tree.
1.1. Check out from Subversion, check in to Mercurial
The first goal is to download a copy of the current Subversion tree and check it into a repository I'll call trunk. I'll use the Python "py3k" branch as my example Subversion repository.
% svn co http://svn.python.org/projects/python/branches/p3yk trunk % hg init trunk % cd trunk % hg branch trunk
Next create a .hgignore in that directory and add the following lines:
syntax: glob .svn
Tip: If you want to add more stuff to your .hgignore, do it here in the trunk repository. That way it won't show up later when you run diffs against the original.
Now check in everything:
% hg add % hg ci
The trunk branch is now ready. This branch should only be used as a mirror of the Subversion repository, and should otherwise be treated as "read-only".
1.2. Branch to your work repository
I'm doing work on concatenation, so I'll create a branch called concat where I'll create my patch.
% cd .. % hg clone trunk concat % cd concat % hg branch concat
The concat branch is now ready for work; you may start editing and checking in all you like.
1.3. Updating Your Branch From Subversion
Here's how to pull changes from the Subversion repository into your workspace. First, update your trunk branch from the Subversion repository:
% cd trunk % svn update % hg addremove % hg ci
Next, pull those changes into your concat branch:
% cd ../concat % hg pull ../trunk % hg merge
Tip: it's probably easiest to do this when you don't have any outstanding edits.
1.4. Generating A Patch
What you really want to do is generate a local "diff" against the tip revision in the trunk branch. Because we named our branches, and we have all the trunk revisions in concat, this is easy:
% cd concat % hg diff -r trunk -r tip
2. Stacking Patches
It's easy to make a patch that's dependent on another patch; just hg clone from your work branch instead of the Subversion mirror branch. For instance, I want to make a slice patch that depends on my concat patch. I do this:
% hg clone concat slice % cd slice % hg branch slice
All the other steps work like the above, except you use the concat branch instead of the trunk branch. Run hg pull ../concat to update the slice branch, and hg diff -r concat -r tip to generate a patch. (Or hg diff -r trunk -r tip to generate a cumulative "rollup" patch with the changes from both concat and slice!)
3. Why Not Queues?
You can use Mercurial's queues extension to achieve much the same result. There are several advantages of using queues: there are fewer steps involved in several of the processes, and because you only need one repository you can use less disk space. The main disadvantage is that you can't easily track the history of commits to your patches.