Feature Branching and Merging

A feature branch, as defined in the Subversion manual, is...

...a temporary branch created to work on a complex change without interfering with the stability of /trunk. [...] Feature branches are born, used for a while, merged back to the trunk, then ultimately deleted. They have a finite span of usefulness.

The same page provides a good rule of thumb for when to create feature branches:

if the developer worked for days in isolation and then committed the large change all at once (so that /trunk were never destabilized), would it be too large a change to review? If the answer to that question is β€œyes”, then the change should be developed on a feature branch. As the developer commits incremental changes to the branch, they can be easily reviewed by peers.

The following are instructions for how to create, work with, and ultimately end a feature branch. The instructions use the Subversion command line client (svn), which is currently the recommended method. Insofar as you can recreate these steps using your favorite Subversion client, using such a client is probably fine. However, a more automated procedure is not recommended, e.g. using an Eclipse plugin's automated branching and merging functionality, as we have not yet had success with this.

Setup

The procedure to create a branch is simply to copy the trunk as a new directory under /branches:

$ svn copy https://trondheim.cs.washington.edu/svn/opus/trunk \
           https://trondheim.cs.washington.edu/svn/opus/branches/new_feature_branch \
      -m "Created a new feature branch"

In this case the branch would be called "new_feature_branch". You would probably want a more descriptive log message.

Now you can check out your new feature branch as usual:

$ svn checkout https://trondheim.cs.washington.edu/svn/opus/branches/new_feature_branch

Syncing the Feature Branch with the Trunk

You need to make sure that your feature branch stays current with development going on in the trunk. Therefore, you should periodically (e.g. weekly) merge trunk changes into your feature branch.

To do this, you need to know the revision of the trunk that your branch is in sync with, and the current revision of the trunk.

The First Sync

The first time you sync your feature branch with the trunk, the trunk revision you are looking for is the revision of the initial branching. You can find this revision using:

$ svn log --stop-on-copy https://trondheim.cs.washington.edu/svn/opus/branches/new_feature_branch

This will give all the log messages on the feature branch back to its creation. The oldest (i.e. last to print) log message will tell you the revision of the initial branching:

[...]
------------------------------------------------------------------------
r2904 | theuser | 2008-03-06 17:30:11 -0800 (Thu, 06 Mar 2008) | 1 line

Created a new feature branch
------------------------------------------------------------------------

So you would use the very next revision as the starting revision: 2905.

Next you need to know the most recent revision, and then do the merge:

$ cd new-feature-branch
$ svn update
At revision 3011.

$ svn merge -r 2905:3011 https://trondheim.cs.washington.edu/svn/opus/trunk

(You may note that even though you are updating in the branch, the reported revision will be the most recent repository-wide revision number.)

Now you would resolve any conflicts that arose in the merge, run tests, etc. When you are satisfied with the newly synced branch, you should check it in as usual, except that your commit message should follow a standard format:

$ svn commit -m "Merged trunk changes r2905:3011 into new-feature-branch"

If you always use this format for the commit message, you'll find it much easier to sync the branch with the trunk again in the future.

Subsequent Syncs

For subsequent syncs with the trunk, you can figure out the starting revision number from your helpful commit message:

$ svn log --stop-on-copy \
      https://trondheim.cs.washington.edu/svn/opus/branches/new_feature_branch | grep "^Merged"
Merged trunk changes r2905:3011 into new-feature-branch

The first (i.e. more recent) "Merged..." commit message is the one you want. So in this case, you start on the next revision after the one you synced up to: 3012. Everything else proceeds as before:

$ cd new-feature-branch
$ svn update
At revision 3018.

$ svn merge -r 3012:3018 https://trondheim.cs.washington.edu/svn/opus/trunk

# ...resolve conflicts, do tests, etc...

$ svn commit -m "Merged trunk changes r3012:3018 into new-feature-branch"

Merging the Feature Branch into the Trunk

At some point it will be time to merge the changes done in your feature branch into the trunk. The basic plan is to first make sure your feature branch is synced with the current trunk, and then merge the differences between the trunk and your feature branch into the trunk (since, because they are synced, the differences only are the changes made to your feature branch).

Syncing proceeds basically identically as in the previous section, except you also want to update your checkout of the trunk:

$ cd path/to/opus/trunk
$ svn update
At revision 3024.

From here, proceed to sync the branch with the trunk as described in the previous section, but with a caveat: use the revision of your checked-out trunk for the merge's end-point (in this case, 3024), as opposed to whatever revision you get when updating your feature branch checkout. Also, when you commit your synced feature branch, note the revision number of the commit. We'll assume it is 3025.

Now that the feature branch is synced with the trunk, you can just merge the differences between the branch and the trunk into the trunk:

$ cd path/to/opus/trunk
$ svn merge https://trondheim.cs.washington.edu/svn/opus/trunk@3024 \
            https://trondheim.cs.washington.edu/svn/opus/branches/new_feature_branch@3025

Notice that you should specify the revision of the trunk as the one the feature branch is synced to (and the revision you currently have checked out), and the revision of the branch as the one that is synced with the trunk. This prevents any issues arising from someone else committing changes to the repository while you are engaged in the merging process.

Now you should resolve any conflicts that arose in the merge, run tests, etc. When you are satisfied with the newly feature-merged trunk, you can check in your changes as usual:

$ svn update
At revision 3025.  # Assuming nobody committed anything in the mean time.

$ svn commit -m "Merged new_feature_branch into trunk"

At this point, typically the feature branch is now "dead" and should be deleted:

$ svn delete https://trondheim.cs.washington.edu/svn/opus/branches/new_feature_branch \
      -m "Deleted new_feature_branch now that it has been merged with trunk"