Notice: this article is extremely out of date. If you want to learn modern Subversion best practices, please look elsewhere.
You want to make a Subversion branch, and merge it later. You read the branching section in the official book, but are still confused. What to do?
creating the branch
1. Note the current head revision:
svn info svn://server.com/svn/repository/trunk | grep Revision
2. Make a clean, remote copy of trunk
into the branches
folder. Name it something. We’ll call it your_branch
:
svn cp svn://server.com/svn/repository/trunk \
svn://server.com/svn/repository/branches/your_branch \
-m "Branching from trunk to your_branch at HEAD_REVISION"
Replace HEAD_REVISION
with the revision number you noted in step 1.
Note that a backslash (\
) means that the command continues onto the next line.
3. switch
your local checkout to point to the new branch (this will not overwrite your changes):
svn switch --relocate \
svn://server.com/svn/repository/trunk \
svn://server.com/svn/repository/branches/your_branch
You don’t really need the --relocate svn://server.com/svn/repository/trunk
bit, but I’m in the habit of being explicit about it.
4. Check that your local checkout is definitely now your_branch
, and that you can update ok:
svn info | grep URL
svn up
5. commit
your new changes.
(These steps will work even if you had already made local changes on trunk
, but decided you wanted them on your_branch
instead. If your trunk
checkout was unmodified, just skip step 5.)
updating the branch
You’ve been developing for a while on your_branch
, and so have other people on trunk
, and now you have to add their changes to your_branch
.
1. First, update
your branch checkout and commit
any outstanding changes.
2. Search the Subversion log to see at what revision number you last merged the changes (or when the original branch was made, if you’ve never merged). This is critical for making a successful merge:
svn log --limit 500 | grep -B 3 your_branch
3. Also note the current head revision:
svn info svn://server.com/svn/repository/trunk | grep Revision
4. Merge the difference of the last merged revision on trunk
and the head revision on trunk
into the your_branch
working copy:
svn merge -r LAST_MERGED_REVISION:HEAD_REVISION \
svn://server.com/svn/repository/trunk .
Replace LAST_MERGED_REVISION
with the revision number you noted in step 2, and HEAD_REVISION
with the revision number you noted in step 3.
Now look for errors in the output. Could all files be found? Did things get deleted that shouldn’t have been? Maybe you did it wrong. If you need to revert, run svn revert -R *
.
5. Otherwise, if things seem ok, check for conflicts:
svn status | egrep '^C|^.C'
Resolve any conflicts. Make sure the application starts and the tests pass.
6. commit
your merge.
svn ci -m "Merged changes from trunk to your_branch: COMMAND"
Replace COMMAND
with the exact command contents from step 4.
Phew.
folding the branch back into trunk
Hey, your_branch
is done! Now it has to become trunk
, so everyone will use it and see how awesome it is.
This only happens once per branch.
1. First, follow every step in the previous section (“updating the branch”) so that your_branch
is in sync with any recent changes on trunk
.
2. Delete trunk
completely:
svn del svn://server.com/svn/repository/trunk
3. Move your_branch
onto the old trunk
location:
svn mv svn://server.com/svn/repository/branches/your_branch \
svn://server.com/svn/repository/trunk
4. Relocate your working copy back to trunk
:
svn switch --relocate \
svn://server.com/svn/repository/branches/your_branch \
svn://server.com/svn/repository/trunk
All done.
footnote
Subversion 1.5 is scheduled to bring automatic merge tracking (notice the ticket comment that says “tip of the iceberg”). Until that fine day, if you want to automate this, the svnmerge.py tool is supposed to be pretty nice.
Why are you deleting
trunk
when “folding in the branch”? What if othertrunk
changes have occurred?So instead of putting
trunk
->branch
the final time, putbranch
->trunk
, and then kill the branch if you have to. (My branches hang around in my SVN like a bad smell, I should clean them out.)cheat svnmerge
Or, view it online here.
Nic, that’s why I said to update
your_branch
fromtrunk
before doing the final fold.Since
your_branch
already hastrunk
changes in it by this point, it’s difficult to do a clean reverse merge ontotrunk
—you get oldtrunk
changes duplicated onto itself, and things go sour.Most of this is done for you, intelligently, by Git. Git even has an SVN wrapper for committing and checking out from SVN repos. If branching is something you do often, check it out.
I’m wary of combining two version control systems on a large project; it seems like it would be even more brittle.
That said, if it works for you, go for it.
I would recommend that you check out svnauto—it’s Subversion automation at its finest. It automates and standardizes branching and merging operations.
Ben, I did, some time ago. Has the bug that prevents you from updating an experimental branch from
trunk
been fixed?It must be as I have never encountered that issue and do it on almost a daily basis. ;)
“Since branch already has trunk changes in it by this point, it’s difficult to do a clean reverse merge onto
trunk
—you get old trunk changes duplicated onto itself, and things go sour.”That’s not true at all.
Once you’ve done all your work in your branch, and merged all the changes that have been made on
trunk
in the meantime, thediff
between your branch andtrunk
is just the changes you’ve made.You then merge your branch into
trunk
,trunk
ends up with the changes you’ve made. Then you justcommit
with the message “merged such-and-such branch into trunk.”I was talking about a merge of historical changesets from the branch, not a cross merge (which still requires the branch update first, as you note). You can do a cross merge if you want, but it’s simpler to just
move
the branch ontotrunk
.Cross merge used to cause me trouble when files had been deleted and then re-added with the same name (among other things). You say it’s a worst practice, but
move
has caused me far less problems than trying to take thediff
of arbitrary, divergent SVN trees.I understand that a cross merge is the “official” way to do it. I disagree that it’s best.
It matters, though, because otherwise you lose a bunch of change history from your
trunk
.In a cross merge, though, you lose the history from
your_branch
. Neither way is perfect.Note that if you do decide to do a cross merge, you have to take the
diff
oftrunk
andyour_branch
, notyour_branch
andtrunk
. The second way will definitely blow up.You need to do (from within a
trunk
working directory):Nice writeup, evan, very comprehensive. I just got through with some major merging headaches at work. In the end a cross merge ended up working best for me. The command from your previous comment was the ticket as was making sure the branch was in sync w/ the trunk.
Regarding cross merges, I think it is definitely more important to keep change history from trunk. Here is how I see it:
A development branch is useful when you are making a change that will involve many commits and will be generally unstable in the interim. This is true regardless of your development process.
If you enforce it at a process level, trunk can be a stable “always-buildable” cut of the latest-n-greatest. Development that’s as simple as a single commit (e.g. “fix a typo in log message”) can go in here, possibly with a pre-commit check to verify that it builds and passes smoke tests.
With this combination, you do as much work as you want “on the side”, but then in one fell swoop you merge it into your trunk. The result of this is that the svn history in branches typically contains lots of “churn” and small changes, whereas svn history in trunk contains more high-level changes. Thus, the trunk revision log is more useful because it contains the logical set of stuff that’s happened in the source tree, rather than the nitty-gritty details of “changed this function name”, “reordered parameters”, “fixed whitespace”, etc.
This style of development won’t always match the group, so take everything I just said with a big grain of salt (^:
Between the “updating the branch” and “folding the branch back into trunk” steps, people’s work will be destroyed if you don’t tell everyone sharing the repository to stop working. Beyond a handful of people are working in the same room, this is impractical, and happens to be the very problem version control was designed to address.
Merge from branch to trunk, never delete trunk.