This section is from the "Version Control with Subversion" book, by Ben Collins-Sussman, Brian W. Fitzpatrick and C. Michael Pilato. Also available from Amazon: Version Control with Subversion.
Continuing with our running example, let's suppose that a
week has passed since you started working on your private
branch. Your new feature isn't finished yet, but at the same
time you know that other people on your team have continued to
make important changes in the
project's /trunk
. It's in your best
interest to replicate those changes to your own branch, just
to make sure they mesh well with your changes. In fact, this
is a best practice: by frequently keeping your branch in sync
with the main development line, it helps
prevent “surprise” conflicts when it comes time
for you to fold your changes back into the trunk.
Subversion is aware of the history of your branch and knows when it divided away from the trunk. To replicate the latest, greatest trunk changes to your branch, first make sure your working copy of the branch is “clean”—that it has no local modifications reported by svn status. Then simply run:
$ pwd /home/user/my-calc-branch $ svn merge http://svn.example.com/repos/calc/trunk --- Merging r345 through r356 into '.': U button.c U integer.c
Your branch working copy now contains new local modifications, and these edits are duplications of all of the changes that have happened on the trunk since you first created your branch:
$ svn status M button.c M integer.c
At this point, the wise thing to do is look at the changes carefully with svn diff, and then build and test your branch. You might need to resolve some conflicts (just as you do with svn update) or possibly make some small edits to get things working properly. (Remember, just because there are no syntactic conflicts doesn't mean there aren't any semantic conflicts!) If you encounter serious problems, you can always abort the local changes by running svn revert and start a long “what's going on?” discussion with your collaborators. If things look good, however, then you can submit your changes into the repository:
$ svn commit -m "Merged latest trunk changes to my-calc-branch." Sending button.c Sending integer.c Transmitting file data .. Committed revision 357.
At this point, your private branch is now “in sync” with the trunk, so you can rest easier knowing that as you continue to work in isolation, you're not drifting too far away from what everyone else is doing.
Suppose that another week has passed. You've committed more changes to your branch, and your comrades have continued to improve the trunk as well. Once again, you'd like to replicate the latest trunk changes to your branch and bring yourself in sync. Just run the same merge command again!
$ svn merge http://svn.example.com/repos/calc/trunk --- Merging r357 through r380 into '.': U integer.c U Makefile A README
Subversion knows which trunk changes you've already replicated to your branch, so it carefully replicates only those changes you don't yet have. Once again, you'll have to build, test, and svn commit the local modifications to your branch.
What happens when you finally finish your work, though? Your new feature is done, and you're ready to merge your branch changes back to the trunk (so your team can enjoy the bounty of your labor). The process is simple. First, bring your branch in sync with the trunk again, just as you've been doing all along:
$ svn merge http://svn.example.com/repos/calc/trunk --- Merging r381 through r385 into '.': U button.c U README $ # build, test, ... $ svn commit -m "Final merge of trunk changes to my-calc-branch." Sending button.c Sending README Transmitting file data .. Committed revision 390.
Now, you use svn merge to replicate
your branch changes back into the trunk. You'll need an
up-to-date working copy of /trunk
. You
can do this by either doing an svn
checkout, dredging up an old trunk working copy from
somewhere on your disk, or by using svn
switch (see
the section called “Traversing Branches”.) However you get a
trunk working copy, remember that it's a best practice to do
your merge into a working copy that
has no local edits and has been recently
updated. If your working copy isn't “clean” in
these ways, you can run into some unnecessary conflict-related
headaches.
Once you have a clean working copy of the trunk, you're ready merge your branch back into it:
$ pwd /home/user/calc-trunk $ svn merge --reintegrate http://svn.example.com/repos/calc/branches/my-calc-branch --- Merging r341 through r390 into '.': U button.c U integer.c U Makefile $ # build, test, verify, ... $ svn commit -m "Merge my-calc-branch back into trunk!" Sending button.c Sending integer.c Sending Makefile Transmitting file data .. Committed revision 391.
Congratulations, your branch has now been re-merged back
into the main line of development. Notice our use of
the --reintegrate
option this time around.
The option is needed because this sort of “merge
back” is a different sort of work than what you've been
doing up until now. Previously, we had been
asking svn merge to grab the “next
set” of changes from one branch and duplicate them to
another. This is fairly straightforward, and each time
Subversion knows how to pick up where it left off. In our
prior examples, you can see that first it merges the ranges
345:356 from trunk to branch; later on, it continues by
merging the next contiguously available range, 356:380. When
doing the final sync, it merges the range 380:385.
When merging your branch back to the trunk, however, the
underlying mathematics is quite different. Your feature
branch is now a mish-mosh of both duplicated trunk changes and
private branch changes, so there's no simple contiguous range
of revisions to copy over. By specifying
the --reintegrate
option, you're asking
Subversion to carefully replicate only
those changes unique to your branch. (And in fact it does
this by comparing the latest trunk tree with the latest branch
tree: the resulting difference is exactly your branch
changes!)
Now that your branch is merged to trunk, you'll no longer need your branch. You can destroy your working copy of the branch, and also do some basic housecleaning in the repository:
$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch Committed revision 392.
But wait! Isn't the history of that branch valuable?
What if somebody wants to audit the evolution of your feature
someday and look at all of your branch changes? No need to
worry. Remember that even though your branch is no longer
visible in the /branches
directory, its
existence is still an immutable part of the repository's
history. A simple svn log command on
the /branches
URL will show the entire
history of your branch. Your branch can even be resurrected
at some point, should you desire (see
the section called “Resurrecting Deleted Items”).