Subversion/branching guide

Making a branch
A branch in Subversion is "just" a copy of an already-existing directory tree which can be further edited independently. On the one hand this gives you more flexibility than, say, CVS, but on the other hand you sometimes have to have a little discipline to keep things sorted right.

Release branch example
For our quarterly releases, I make a branch directory and then copy MediaWiki's "phase3" directory off the current trunk:

svn mkdir svn+ssh://svn.wikimedia.org/svnroot/mediawiki/branches/REL1_8 svn copy \ svn+ssh://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3 \ svn+ssh://svn.wikimedia.org/svnroot/mediawiki/branches/REL1_8/phase3 svn copy \ svn+ssh://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions \ svn+ssh://svn.wikimedia.org/svnroot/mediawiki/branches/REL1_8/extensions

Then, for each individual release I make another copy which can be referenced to pull that particular version of the branch: svn copy \ svn+ssh://svn.wikimedia.org/svnroot/mediawiki/branches/REL1_8 \ svn+ssh://svn.wikimedia.org/svnroot/mediawiki/tags/REL1_8_0

SVN has no specific concept of "tags" like CVS does; "branches" and "tags" are just directory names, and how their contents are treated is a matter of convention. Thus it's actually possible to make further changes to a tag; this is occasionally useful (for instance, to clean up some file corruption from botched line-ending conversions when we converted from CVS to SVN) but usually you should not alter things labeled as tags.

Merging trunk changes into your branch
To keep a work branch up to date, or to quickly merge an individual fix into a release branch, you can use Subversion's "merge" command.

This unfortunately likes big long URLs which are a pain to type, but some common cases can be simplified quite a bit; I find this shell script rather handy:

Listing 1: mw-merge
 * 1) !/bin/bash

if [ "x$2" == "x" ] then current="$1" let prev="$current - 1" else prev="$1" current="$2" fi svn merge -r$prev:$current svn+ssh://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3

When run in a branch's working directory, this script merges either a single change from trunk (if given one revision number), or all changes on trunk from a start to an end revision into the working directory.

You may have to manually resolve conflicts, of course; see the online subversion documentation for some general hints.

Once conflicts are resolved, use 'svn commit' to commit the updates into the branch -- preferably before you do further work, to simplify your life when looking at the history later. I strongly recommend including the revision numbers you merged against in the commit comment, to remind yourself what you did (and where you'll have to work from next time!)

In fact, it's probably best if you use a tool such as svnmerge.py to keep track of this for you. Using a tool eliminates the very probable event of an error in merging, as well as the great tedium.

Merging branch changes into trunk
When your work branch is complete and ready for prime-time, you'll want to merge into trunk. Test and consult with others first if it's big and scary... but don't feel bad if you get reverted right away! Big changes might need fixes or further review before being finally accepted.

I find a useful workflow is to first make a diff from current trunk to the branch state, review that manually, and then once I'm satisfied I use the standard 'patch' command to apply the diff onto trunk.

You should also be able to use 'svn merge' as with the above merge-from-trunk script, though.