|Ned Batchelder : Blog | Code | Text | Site|
Subversion branching quick start
» Home : Text
Created 29 October 2006
Many developers are uneasy about branching and merging, even those who consider source control essential. It can be a very complicated process, but it doesn't have to be, and it is a very powerful way to manage development. Here's how to get started with branches in Subversion.
Branching produces a split in a code stream: different developers can be working in alternate universes of the same set of code. Changes are made independently to each stream. Merging brings changes back together to combine the streams. There are a number of reasons why you might want to use branches, and different reasons produce different kinds of branches.
Branching is a powerful tool in managing development and releases. There are many different styles of branching, but I've only ever needed two: Fixes and Features, which I'll describe below. These are simple, and fill 90% of the need for branching. Don't go overboard with elaborate branches. Purists will develop complex theories and algebras of branching, with baroque policies and criteria. It doesn't have to be complicated.
One recurring debate is over what goes on the trunk and what goes on the branch. How do you decide what work will happen on the trunk, and what will happen on the branch? Here is my rule:
Branches are for the minority.
Using a branch is always more involved than using the trunk, so the trunk should be used by the majority, and the branch should belong to the minority. Subversion is easier than other source control systems in this regard, but the rule still holds: when trying to decide what goes on the trunk and what goes on the branch, put the code that most developers want on the trunk, and put the minority on the branch.
Subversion makes branching a simple process. If you set up your repository following the Subversion guidelines, you have a trunk/ directory and a branches/ directory. There's nothing magical about these directories, so if you don't have them, you can put your branch anywhere you like.
You'll use the svn copy command to copy the trunk as a branch. This doesn't actually copy any files until changes are made, so don't worry about disk space.
That's it. Now you have a directory at /work/branches/mybranch where you can do whatever work you need to do.
The example above branched from the tip of the trunk (what Subversion calls HEAD). You can also branch from a particular past revision by specifying the -r argument with a revision number.
Working with your branch is exactly the same as working on the trunk. You use svn update to get the latest code from the repository, you edit files, and you use svn commit to check in code to the repository.
Subversion doesn't make any fundamental distinction between branches and trunk. All changesets go into the same list of changesets, each with its own sequential revision number. This is because a Subversion revision number represents a revision of the entire repository, not of a single file.
At some point, you will need to bring changes from the trunk over to your branch, or from your branch back to the trunk, or even between two branches. This process is called merging.
The svn merge command accomplishes this. You specify a range of revisions, a source path, and a destination path, and Subversion brings all those changes from the source onto the destination. For example, suppose we're still working with the mybranch branch we created above. We can issue a merge command:
This finds all the changes in changesets 1775, 1776, and 1777 that were made in the trunk tree, and re-applies them in the mybranch tree. It shows which files are being updated as it works. The changes are made in your working directory, and have to be checked in like any other change:
One thing to note: the svn merge command requires a range of revision numbers. If you want to apply the changes from a single changeset, you still have to supply two revision numbers. Merging the changes from changeset 1962 is accomplished with -r1961:1962, for example. Yes, this is silly. Maybe Subversion will change in the future to accept one revision number for a single changeset.
This example shows merging trunk changes to the branch, but the merge can also be used to bring branch changes to the trunk, just by swapping the source and destination arguments.
When merging, you may encounter conflicts. These can happen in normal development, but are more likely with branches, especially long-lived branches. In addition to the usual ways of getting conflicts, where two developers change the same part of a file, merging introduces a new way to get a conflict. If a file has been modified twice on the trunk, and you try to merge only the second of the changes, Subversion may report a conflict.
Different branch types
There are many different ways to use branches in software development. In fact, there are enough to fill a small book devoted to the subject. Don't worry about all of that. There are two branch types which solve most development problems:
These two types of branches have different use patterns involving branch point, merge policy, and lifetime. We'll examine them each in turn.
A fixes branch (or maintenance branch) is used to apply bug fixes to a shipped version of the code. It lets you release follow-on versions of the software with bug fixes without having to incur the risk of shipping partially finished features.
Branching: the branch is created from the revision that actually shipped. This guarantees that no extra changes have accidentally slipped into your maintenance release. Use the -r argument to the svn copy command to ensure that you have the proper starting point. The branch should be named with the version number or revision number it branched from: fixes_v2_1, or fixes1234, for example.
Changes: For the most part, fixes are made on the trunk, then merged to the branch. This is because most fixes are appropriate to the trunk, and are chosen for inclusion in the maintenance release. Occaisionally, you may have to fix a bug in a maintenance release in a way that differs from how you would fix it on the trunk, because of changes in the trunk since you shipped. In that case, make the change directly on the fixes branch.
Merging: Only merge from the trunk to the branch. This is one of the reasons to make fixes on the trunk first. By keeping all the merging in only one direction (trunk to branch), you simplify the process and reduce the possibility of conflicts.
Merges will be done only for specific changesets, those with the bug fixes that should be included in the maintenance release. The merges will therefore be sparse, picking and choosing only those changes needed. The longer the branch is active, the greater possibility that a merge will not be possible because of conflicts introduced by missing changes from the trunk.
Lifetime: The lifetime of a fixes branch depends on your release model. If you are building a web site or other software that is "shipped" to only one place, the fixes branch will be obsoleted the next time you deploy the trunk. In a more traditional model, the fixes branch will have to stick around for a long time, until you end support for that version of the product.
A popular variant of the fix branch is a release branch: as development nears the point of releasing, a branch is created for the final polishing. This is fine to do so long as it doesn't violate the trunk-majority rule. If everyone is still working on polishing, and all of that work will be merged back to the trunk, there's no point branching yet.
A feature branch is used by developers creating a major feature, or one which is speculative, and may not be included in the product. Using one or more feature branch allows your developers to work independently of each other while still using Subversion as a way to share their work within the feature group.
The feature branch is generally kept up to date with the trunk as work progresses. Once the feature is done, the whole branch is merged back to the trunk.
Branching: the starting point of a features branch is less sensitive than with a fixes branch. When feature work begins, branch from the head, and dive in. Give the branch a descriptive name based on the feature, for example, 3d_ui.
Changes: the changes on the feature branch are whatever work has to happen to implement the feature. Make the changes on the branch and check them in.
Merging: the bulk of the merging on the feature branch will be to bring trunk changes over to keep the feature branch current with the trunk. These merges are a periodic maintenance task on the branch, for example, done once a week or so.
Subversion doesn't record the history of merging, so to do this periodic trunk update, you have to manually note which revision you are current with. For example, when the branch is created, note the revision:
When the time comes to merge the trunk over, you merge from there, including everything from the latest trunk revision merged, to the head:
After another interval of work (week, month, whatever is appropriate to your environment), you'll have to merge again to get the recent changes to the trunk. Again, you'll specify a revision range that takes only the changes you haven't already merged:
The checkin comments are important here, because they are the simplest way to keep track of what the latest merge revision was.
Eventually, the feature is done, and needs to be merged back to the trunk. Now you will merge all of the revisions from the branch point to the head from the branch back to the trunk:
Lifecycle: at this point, the feature branch is done. You can go back to working on the trunk, or creating a new branch for the next big thing.
That's basically all you need to know, but here are some other pointers:
Don't be scared
Branching and merging is more complicated than simply making changes to a single line of development. But once you establish some patterns, and get in the habit of working with branches, it is not difficult. They are powerful tools that let you be more thoughtful in what code gets put where, and how many developers have to deal with any given set of changes.