Subversion branching quick start
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.
Principles
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.
Branching
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.
- Decide on a name for the branch. It should be short and descriptive, and usable as a directory name. In these examples, it’s “mybranch”.
- Use the svn copy command to create the branch in the repository by copying the trunk.
The arguments are a destination path and a source path. The svn info command may
be helpful to remind yourself what your repository path is.
Here’s an example that creates the mybranch branch from the trunk:
The change is committed immediately. Because this command uses repository paths, it changed the repository directly, with no effect on your working directory.$ svn copy http://svn.myrepo.com/trunk http://svn.myrepo.com/branches/mybranch
Committed revision 1701. - To get a working directory for your branch, you can simply go to your
branches/ working directory and update to get the new branch:
If you haven’t checked out the branches directory, you can use the svn checkout command to get it or just the mybranch directory:$ cd /work/branches
$ svn up$ mkdir /work/branches
$ svn co http://svn.myrepo.com/branches/mybranch
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
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.
Merging
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:
$ svn merge -r1774:1777 /work/trunk /work/branches/mybranch
U mybranch/source/hello.py
U mybranch/source/util.py
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:
$ svn ci -m "[mybranch] Merged 1774:1777 from the trunk" mybranch
Sending mybranch/source/hello.py
Sending mybranch/source/util.py
Transmitting file data ..
Committed revision 1810.
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:
- Fixes Branch: while feature work continues on the trunk, a fixes branch is created to hold the fixes to the latest shipped version of the software. This allows you to fix problems without having to wait for the latest crop of features to be finished and stabilized.
- Feature Branch: if a particular feature is disruptive enough or speculative enough that you don’t want the entire development team to have to suffer through its early stages, you can create a branch on which to do the work.
These two types of branches have different use patterns involving branch point, merge policy, and lifetime. We’ll examine them each in turn.
Fixes branches
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. Occasionally, 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.
Feature branches
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:
$ svn copy http://svn.myrepo.com/trunk http://svn.myrepo.com/branches/3d_ui
Committed revision 1701.
When the time comes to merge the trunk over, you merge from there, including everything from the latest trunk revision merged, to the head:
$ svn update
At revision 1812.
$ svn merge -r1701:1812 /work/trunk /work/branches/3d_ui
U 3d_ui/source/hello.py
...
$ svn ci -m "[3d_ui] Merged the trunk from 1701 to 1812."
Sending 3d_ui/source/hello.py
...
Transmitting file data ..
Committed revision 1813.
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:
$ svn update
At revisioun 1865.
$ svn merge -r1812:1865 /work/trunk /work/branches/3d_ui
U 3d_ui/source/util.py
...
$ svn ci -m "[3d_ui] Merged the trunk from 1812 to 1865."
Sending 3d_ui/source/util.py
...
Transmitting file data ..
Committed revision 1866.
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:
$ svn update
At revision 1911.
$ svn merge -r1701:1911 /work/branches/3d_ui /work/trunk
U /work/trunk/source/hologram.py
U /work/trunk/source/volume.py
...
$ svn ci -m "Merged the 3d_ui branch back to the trunk."
Sending /work/trunk/source/hologram.py
Sending /work/trunk/source/volume.py
...
Transmitting file data ..
Committed revision 1912.
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.
Miscellaneous tips
That’s basically all you need to know, but here are some other pointers:
- When checking in to the branch, always put the branch name in the comment, so that people can easily tell where the change is happening.
- You can always make a branch from a revision in the past, even far in the past. I’ve often seen developers fret about needing to create a fixes branch before beginning work on new feature work. You don’t have to. Create the fixes branch when you have a fix to put on it, and create it from the last shipped revision, no matter how long ago it was.
- Branches usually have finite lifetimes. For example, a feature branch is obsolete once it has been merged back to the trunk. To keep your branches directory manageable, you can delete the branch when you are done with it. You still have the history of the files in Subversion, and can even retrieve the full branch later if you need it. By deleting the obsolete branches, you let develeopers update from the branches directory without having to wade through unneeded files.
- Subversion’s strange rule about needing two revision number even to merge
a single changelist prompted me to create this one-line script file:
This lets me specify the branch directory and revision number, and it pulls a single changelist from the trunk to the branch.svn merge -r`expr $2 - 1`:$2 ../trunk $1
- If you need to merge only part of a changeset, you have two choices: one is to not merge at all, but simply edit the files on the branch to match the changes made on the trunk. Alternately, you can merge the entire changeset, then manually revert the files you don’t want, or edit files to undo unwanted changes. Remember, the merge command simply edits files in your working tree, so any changes you want to make, you can make by hand.
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.
See also
- The online book Version Control with Subversion.
- Subversion on Windows quick start is my overview of how to get started with Subversion.
- My blog, where other similar topics are discussed.
Comments
If you've got a site and multiple developers working on sub-projects that have radically different lifecycles (say 2 days versus 2 weeks), keep a branch "alive" after every major trunk push for the duration of the longest subproject. If you don't, what ends up happening is the changeset merging can get overwhelming and you end up either trying to "rush" the long leadtime projects or feeling frustrated that the short-term ones aren't getting out soon enough.
In the end you do the same amount of work merging changesets but it is easier when the context is closer to you in time (as in when you've just committed those 9 changesets related to one small bug/feature) than when you've got a 80 changesets to review while you are already feeling under the gun to push.
On a dev team with an official release manager this would be a no-brainer for me— in our case where we don't quite have that level of resources, it's more of a trade-off and should be made only when the delta in times of the subprojects calls for it.
Otherwise drink this article in— it's a wealth of knowledge that I wish I'd had with me three jobs ago.
Most of your advice seems to be from the viewpoint of developing with a small team. For example "Branches are for the minority" I disagree with if applying to a large (even 10+) team. I work with a group of around 25 developers and if we avoided branches it would be chaos. As such, my rule differs a little: "always branch". :)
"This finds all the changes in changesets 1775, 1776, and 1777" is somewhat misleading: the merge command you supplied will certainly merge the changeset between 1774:1777 but that may not specifically include 1775, 1776 and 1777. The revisions must have occurred on the trunk (which isn't guaranteed - they may have occurred on a different branch).
I'm not sure I understand why the branch name should be added to a revision comment. It's pretty easy to find out what has changed (and where) if you need to.
I guess I don't agree that the two required revision numbers is "silly". It actually makes more sense to me than using a single revision number...it's consistent and clear what you're merging. I wouldn't recommend anyone in my team use a single revision number (like with your script), I'd prefer them to commit changes to their branches regularly and merge the changes that they intend.
And, while I understand this is a beginners guide, the switch command is extremely useful when merging.
Overall though, a great article - thanks!
One thing that MattyT mentioned in the comments was the "switch" command. This is still something I don't understand. The tortoise docs (section 5.16.2) try to explain it. The man page may provide a clue:
...Update the working copy to mirror a new URL within the repository. This behaviour is similar to 'svn update', and is the way to move a working copy to a branch or tag within the same repository.
So is the switch command (or the option in the tortoise branch/tag dialog?) basically to mirror your working copy from one location to another? ie, you've made uncommitted WC changes to /trunk and you want to copy those changes into a new branch in your WC?
Sorry, I don't quite get it yet :)
We usually make changes on the fix branch first, then merge them to the trunk. We consider it an advantage that any changes done on a fix branch should probably exist on the trunk. Since changes to the trunk may not belong on a branch, it seems a bit more error prone.
I.E. You can take a weeks worth of bug fixes on a fix branch and safely merge them onto the trunk. Vice-versa is probably not true since it is likely to contain bug fixes along with new development.
Wouldn't you agree this is a significant advantage for merging from the fix branch to the trunk?
Thanks for any feedback, and again, thanks for the well written and informative article,
- Andy.
- Andy.
Check out Linus' presentation about git at a Google Tech Talk. [0]
-e
[0] http://video.google.com/videoplay?docid=-2199332044603874737
Thanks!
Conflict resolution is handled by a web-based conflict resolution UI and e-mail notifications.
In addition to Subversion, we also currently support MS Team Foundation Server, and plan on supporting Git, Mercurial, and others in the future.
Check it out at http://www.mergemagician.com
Now this stupid worry about having to merge a bunch of shit after some time is because you do not understand effective use of source control.
What you're SUPPOSED to be doing as a good developer on the team who wants to make life more easy for yourself and your teammates thus changing this evil scary branching to BRANCHING ROCKS, you must do as you always do...but to your branch and that is UPDATE FROM TRUNK TO YOUR BRANCH OFTEN. Yes you might have a few small painful merges each day but at the end when you're ready to commit and merge your branch back to trunk at the end of a feature...guess what...since you merged every day, it's really not much of a hassle at the end because all that work of merging was done DAILY religiously by you the developer.
I've done this and it works great. I often have 4-5 branch folders locally and because I do what I'm supposed to be done as a good developer using branching properly by religiously merging from trunk to branch EVERY DAY or even several times a day, I don't even have to worry about the shit you guys are arguing about with this merge hell.
And @Coffee, maybe you wouldn't have "painful merges every day" if you took the time to read Ned's article. Try it, you might learn something ;)
Thank you for the clear article on branching AND the comments, after reading i tried various situations, and everything is resolvable now ;)
I am currently writing a short manual for my coworkers and hopefully redefine the SVN policy.
Thanks Author and commenters ;)
Add a comment: