 |
Home | Changes | Index | Search | Go
How to maintain a Subversion feature branch in 15 easy steps
When developing Wonderland, it is often useful to maintain a long-lived feature branch. Most branches in subversion are designed to be short-lived, meaning that a single feature is developed, and then merged back into the trunk. Long-lived feature branches stay around longer, and may participate in multiple cycles where the latest trunk is merged into the feature branch, followed by periodic merges of the feature branch back into the trunk. This mechanism is useful when developing a feature that is large and takes a long period of time to develop, or when maintaining a branch with alternate implementations of part of the trunk that may or may not be eventually merged.
Long-lived feature branches are more complicated to maintain than a typical short-lived branch. They are also potentially more dangerous, because there is the possibility of undoing changes if a merge is done incorrectly. That said, with a little vigilance they can be a very convenient mechanism. For a basic primer on subversion, we recommend the O'Reilly subversion book, which is available for free on the web at: http://svnbook.red-bean.com/.
Below is a quick guide to maintaining a feature branch in subversion:
Creating a branch
1. Branches in subversion are created by copying the trunk.
It's that easy:
# svn mkdir https://wonderland.dev.java.net/svn/wonderland/branches/nigel
# svn cp https://wonderland.dev.java.net/svn/wonderland/trunk https://wonderland.dev.java.net/svn/wonderland/branches/nigel/hud
# svn co https://wonderland.dev.java.net/svn/wonderland/branches/nigel/hud wl-hud
This will create a directory called wl-hud with your branch checked out. If you already have changes in your workspace, and would like these changes to go to your branch instead of trunk, replace the last line with:
# cd wl-hud
# svn switch https://wonderland.dev.java.net/svn/wonderland/branches/nigel/hud
2. After you have created a branch, "svn commit" will commit changes to your branch.
Use "svn info" command to verify the URL you will commit to:
# svn info
...
URL: https://wonderland.dev.java.net/svn/wonderland/branches/jslott
Repository Root: https://wonderland.dev.java.net/svn/wonderland
...
Updating your branch with the latest changes in trunk
1. Commit any outstanding changes you have in your branch.
2. Find the last time your branch was merged with trunk.
If you have updated before, the information you need will be in a subversion commit comment from the previous merge:
# svn log | more
....
------------------------------------------------------------------------
r665 | kaplanj | 2008-10-15 13:35:38 -0700 (Wed, 15 Oct 2008) | 2 lines
Reorganize where voicebridge is stored
------------------------------------------------------------------------
r664 | kaplanj | 2008-10-15 12:24:26 -0700 (Wed, 15 Oct 2008) | 2 lines
Merge rev 626 - 663 from trunk
------------------------------------------------------------------------
r648 | jprovino | 2008-10-14 13:26:56 -0700 (Tue, 14 Oct 2008) | 4 lines
Moved messages to common/messages.
In this case, rev 663 was the last revision of the trunk you were in sync with. If this is the first time you are updating a branch, use the command:
# svn log --stop-on-copy
....
------------------------------------------------------------------------
r699 | jslott | 2008-10-17 17:51:12 -0700 (Fri, 17 Oct 2008) | 2 lines
Recopy trunk to jslott branch
And find the oldest revision it lists. In this case, rev 699 was the branch point, so that was the last revision of the trunk you were in sync with.
3. Find the most recent revision.
"svn update" is the easiest way to do this, since it will print the most recent revision number:
# svn up
At revision 726.
4. Now that we've identified the last time your branch was updated, merge all changes since then:
# svn merge -r 663:726 https://wonderland.dev.java.net/svn/wonderland/trunk
It's important to understand what this command is doing. It is running an "svn diff" between revisions 663 and 726 of trunk, and then applying that change set to your current workspace. This should merge any changes that were made in the trunk with what's in your branch. You can view these changes yourself with the command:
# svn diff -r 663:726 https://wonderland.dev.java.net/svn/wonderland/trunk
Often this will cause conflicts. In some corner cases, especially when files have been moved, it can miss an update. It is therefore important to be aware of the changes you expect in your branch, so you can sanity check the results.
5. Fix any conflicts/build problems/etc. Make sure everything builds properly.
6. Commit changes.
Make EXTRA SURE to include the revisions you are merging in the commit log:
# svn commit
Message: Merge rev 663 - 726 from trunk.
You will refer back to this version number when you do future updates.
Merging your branch back into trunk
1. Update your branch with the latest trunk following the previous directions.
2. Check out an unmodified trunk workspace for merging:
# svn co https://wonderland.dev.java.net/svn/wonderland/trunk wl-merge
3. Merge the changes from your branch.
In the merge workspace, do:
# svn merge https://wonderland.dev.java.net/svn/wonderland/trunk@REV https://wonderland.dev.java.net/svn/wonderland/branches/jp@REV .
where REV is the most recent revision of your branch (the first entry in 'svn log' in you branch workspace). The trick here is that since you already merged your branch with the trunk, the two workspaces should be identical except for the changes you have made. What you are doing here is telling subversion to generate the diffs between your branch and trunk, and then apply those to trunk. This will make trunk identical to your branch. As before, you can generate the diffs yourself using the command:
# svn diff https://wonderland.dev.java.net/svn/wonderland/trunk@REV https://wonderland.dev.java.net/svn/wonderland/branches/jp@REV
4. Review the code changes your are committing.
Now wl-merge will contain the trunk with all the changes you have made on your branch. It is very important that you pay careful attention to what is changed in this workspace. If you run "svn status", it should only report changes you have made in your branch. If you see changes to files you haven't touched, it's a sign that something has gone wrong. If something goes wrong, you will need to go through the commit log for the file you didn't touch, and see where it got changed.
5. Make sure wl-merge builds and runs.
It should be identical to your branch, but it is always worth a double check. Note that 0.5 must compile and run properly from clean using Java 1.5.
6. Commit to trunk using "svn commit" in the wl-merge workspace.
In your commit comment, note the revision of your branch you merged with:
Merged with rev 729 of branch branches/jp
7. The next time you want to update your branch from trunk, you only want to get changes after your merge.
So look for the version you committed in the trunk log. For example, if I saw in the log:
------------------------------------------------------------------------
r641 | kaplanj | 2008-10-13 15:49:53 -0700 (Mon, 13 Oct 2008) | 5 lines
Merge rev 640 from branch branches/jkaplan/build
- add ant deploy task for modules
- update runner web service to allow restarting all services
- add default server URL to core build properties
The next time I go to update my branch, I would use:
# svn merge -r 641:729 https://wonderland.dev.java.net/svn/wonderland/trunk
Note that I use "641", the version of trunk containing my merge, and not "640", which is the version of my branch before the merge.
|