There are many different uses for branching and svn merge, and this section describes the most common ones you're likely to run into.
To complete our running example, we'll move forward in time. Suppose several days have passed, and many changes have happened on both the trunk and your private branch. Suppose that you've finished working on your private branch; the feature or bug fix is finally complete, and now you want to merge all of your branch changes back into the trunk for others to enjoy.
So how do we use svn merge in this
        scenario?  Remember that this command compares two trees, and
        applies the differences to a working copy.  So to receive the
        changes, you need to have a working copy of the trunk.  We'll
        assume that either you still have your original one lying
        around (fully updated), or that you recently checked out a
        fresh working copy of /calc/trunk.
But which two trees should be compared? At first glance, the answer may seem obvious: just compare the latest trunk tree with your latest branch tree. But beware—this assumption is wrong, and has burned many a new user! Since svn merge operates like svn diff, comparing the latest trunk and branch trees will not merely describe the set of changes you made to your branch. Such a comparison shows too many changes: it would not only show the addition of your branch changes, but also the removal of trunk changes that never happened on your branch.
To express only the changes that happened on your branch,
        you need to compare the initial state of your branch to its
        final state.  Using svn log on your branch,
        you can see that your branch was created in revision 341.  And
        the final state of your branch is simply a matter of using the
        HEAD revision.  That means you want to
        compare revisions 341 and HEAD of your
        branch directory, and apply those differences to a working
        copy of the trunk.
A nice way of finding the revision in which a branch was
          created (the “base” of the branch) is to use the
          --stop-on-copy option to svn
          log.  The log subcommand will normally show every
          change ever made to the branch, including tracing back
          through the copy which created the branch.  So normally,
          you'll see history from the trunk as well.  The
          --stop-on-copy will halt log output as soon
          as svn log detects that its target was
          copied or renamed.
So in our continuing example,
$ svn log --verbose --stop-on-copy \
          http://svn.example.com/repos/calc/branches/my-calc-branch
…
------------------------------------------------------------------------
r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
   A /calc/branches/my-calc-branch (from /calc/trunk:340)
$
As expected, the final revision printed by this command
          is the revision in which my-calc-branch
          was created by copying.
Here's the final merging procedure, then:
$ cd calc/trunk $ svn update At revision 405. $ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch U integer.c U button.c U Makefile $ svn status M integer.c M button.c M Makefile # ...examine the diffs, compile, test, etc... $ svn commit -m "Merged my-calc-branch changes r341:405 into the trunk." Sending integer.c Sending button.c Sending Makefile Transmitting file data ... Committed revision 406.
Again, notice that the commit log message very specifically mentions the range of changes that was merged into the trunk. Always remember to do this, because it's critical information you'll need later on.
For example, suppose you decide to keep working on your
        branch for another week, in order to complete an enhancement
        to your original feature or bug fix.  The repository's
        HEAD revision is now 480, and you're ready
        to do another merge from your private branch to the trunk.
        But as discussed in the section called “Best Practices for Merging”, you
        don't want to merge the changes you've already merged before;
        you only want to merge everything “new” on your
        branch since the last time you merged.  The trick is to figure
        out what's new.
The first step is to run svn log on the trunk, and look for a log message about the last time you merged from the branch:
$ cd calc/trunk $ svn log … ------------------------------------------------------------------------ r406 | user | 2004-02-08 11:17:26 -0600 (Sun, 08 Feb 2004) | 1 line Merged my-calc-branch changes r341:405 into the trunk. ------------------------------------------------------------------------ …
Aha!  Since all branch-changes that happened between
        revisions 341 and 405 were previously merged to the trunk as
        revision 406, you now know that you want to merge only the
        branch changes after that—by comparing revisions 406 and
        HEAD.
$ cd calc/trunk $ svn update At revision 480. # We notice that HEAD is currently 480, so we use it to do the merge: $ svn merge -r 406:480 http://svn.example.com/repos/calc/branches/my-calc-branch U integer.c U button.c U Makefile $ svn commit -m "Merged my-calc-branch changes r406:480 into the trunk." Sending integer.c Sending button.c Sending Makefile Transmitting file data ... Committed revision 481.
Now the trunk contains the complete second wave of changes made to the branch. At this point, you can either delete your branch (we'll discuss this later on), or continue working on your branch and repeat this procedure for subsequent merges.
Another common use for svn merge is to
        roll back a change that has already been committed.  Suppose
        you're working away happily on a working copy of
        /calc/trunk, and you discover that the
        change made way back in revision 303, which changed
        integer.c, is completely wrong.  It never
        should have been committed.  You can use svn
        merge to “undo” the change in your
        working copy, and then commit the local modification to the
        repository.  All you need to do is to specify a
        reverse difference:
$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk U integer.c $ svn status M integer.c $ svn diff … # verify that the change is removed … $ svn commit -m "Undoing change committed in r303." Sending integer.c Transmitting file data . Committed revision 350.
One way to think about a repository revision is as a
        specific group of changes (some version control systems call
        these changesets).  By using the
        -r switch, you can ask svn
        merge to apply a changeset, or whole range of
        changesets, to your working copy.  In our case of undoing a
        change, we're asking svn merge to apply
        changeset #303 to our working copy
        backwards.
Keep in mind that rolling back a change like this is just
        like any other svn merge operation, so you
        should use svn status and svn
        diff to confirm that your work is in the state you
        want it to be in, and then use svn commit
        to send the final version to the repository.  After
        committing, this particular changeset is no longer reflected
        in the HEAD revision.
Again, you may be thinking: well, that really didn't undo
        the commit, did it?  The change still exists in revision 303.
        If somebody checks out a version of the
        calc project between revisions 303 and
        349, they'll still see the bad change, right?
Yes, that's true.  When we talk about
        “removing” a change, we're really talking about
        removing it from HEAD.  The original change
        still exists in the repository's history.  For most
        situations, this is good enough.  Most people are only
        interested in tracking the HEAD of a
        project anyway.  There are special cases, however, where you
        really might want to destroy all evidence of the commit.
        (Perhaps somebody accidentally committed a confidential
        document.)  This isn't so easy, it turns out, because
        Subversion was deliberately designed to never lose
        information.  Revisions are immutable trees which build upon
        one another.  Removing a revision from history would cause a
        domino effect, creating chaos in all subsequent revisions and
        possibly invalidating all working copies.
        [10]
      
The great thing about version control systems is that
        information is never lost.  Even when you delete a file or
        directory, it may be gone from the HEAD
        revision, but the object still exists in earlier revisions.
        One of the most common questions new users ask is, “How
        do I get my old file or directory back?”.
The first step is to define exactly which item you're trying to resurrect. Here's a useful metaphor: you can think of every object in the repository as existing in a sort of two-dimensional coordinate system. The first coordinate is a particular revision tree, and the second coordinate is a path within that tree. So every version of your file or directory can be defined by a specific coordinate pair.
Subversion has no Attic directory
        like CVS does,
        [11]
        so you need to use svn
        log to discover the exact coordinate pair you wish
        to resurrect.  A good strategy is to run svn log
        --verbose in a directory which used to contain your
        deleted item.  The --verbose option shows a
        list of all changed items in each revision; all you need to do
        is find the revision in which you deleted the file or
        directory.  You can do this visually, or by using another tool
        to examine the log output (via grep, or
        perhaps via an incremental search in an editor).
$ cd parent-dir $ svn log --verbose … ------------------------------------------------------------------------ r808 | joe | 2003-12-26 14:29:40 -0600 (Fri, 26 Dec 2003) | 3 lines Changed paths: D /calc/trunk/real.c M /calc/trunk/integer.c Added fast fourier transform functions to integer.c. Removed real.c because code now in double.c. …
In the example, we're assuming that you're looking for a
        deleted file real.c.  By looking through
        the logs of a parent directory, you've spotted that this file
        was deleted in revision 808.  Therefore, the last version of
        the file to exist was in the revision right before that.
        Conclusion: you want to resurrect the path
        /calc/trunk/real.c from revision
        807.
That was the hard part—the research. Now that you know what you want to restore, you have two different choices.
One option is to use svn merge to apply
        revision 808 “in reverse”.  (We've already
        discussed how to undo changes, see the section called “Undoing Changes”.)  This would have the effect of
        re-adding real.c as a local modification.
        The file would be scheduled for addition, and after a commit,
        the file would again exist in HEAD.
In this particular example, however, this is probably not
        the best strategy.  Reverse-applying revision 808 would not
        only schedule real.c for addition, but
        the log message indicates that it would also undo certain
        changes to integer.c, which you don't
        want.  Certainly, you could reverse-merge revision 808 and
        then svn revert the local modifications to
        integer.c, but this technique doesn't
        scale well.  What if there were 90 files changed in revision
        808?
A second, more targeted strategy is not to use svn merge at all, but rather the svn copy command. Simply copy the exact revision and path “coordinate pair” from the repository to your working copy:
$ svn copy --revision 807 \
           http://svn.example.com/repos/calc/trunk/real.c ./real.c
$ svn status
A  +   real.c
$ svn commit -m "Resurrected real.c from revision 807, /calc/trunk/real.c."
Adding         real.c
Transmitting file data .
Committed revision 1390.
The plus sign in the status output indicates that the item
        isn't merely scheduled for addition, but scheduled for
        addition “with history”.  Subversion remembers
        where it was copied from.  In the future, running svn
        log on this file will traverse back through the
        file's resurrection and through all the history it had prior
        to revision 807.  In other words, this new
        real.c isn't really new; it's a direct
        descendant of the original, deleted file.
Although our example shows us resurrecting a file, note that these same techniques work just as well for resurrecting deleted directories.
Version control is most often used for software development, so here's a quick peek at two of the most common branching/merging patterns used by teams of programmers. If you're not using Subversion for software development, feel free to skip this section. If you're a software developer using version control for the first time, pay close attention, as these patterns are often considered best practices by experienced folk. These processes aren't specific to Subversion; they're applicable to any version control system. Still, it may help to see them described in Subversion terms.
Most software has a typical lifecycle: code, test, release, repeat. There are two problems with this process. First, developers need to keep writing new features while quality-assurance teams take time to test supposedly-stable versions of the software. New work cannot halt while the software is tested. Second, the team almost always needs to support older, released versions of software; if a bug is discovered in the latest code, it most likely exists in released versions as well, and customers will want to get that bugfix without having to wait for a major new release.
Here's where version control can help. The typical procedure looks like this:
Developers commit all new work to the
                trunk.
              Day-to-day changes are committed to
              /trunk: new features, bugfixes, and
              so on.
The trunk is copied to a
                “release” branch.
              When the team thinks the software is ready for release
              (say, a 1.0 release), then /trunk
              might be copied to
              /branches/1.0.
Teams continue to work in parallel.
              One team begins rigorous testing of the release branch,
              while another team continues new work (say, for version
              2.0) on /trunk.  If bugs are
              discovered in either location, fixes are ported back and
              forth as necessary.  At some point, however, even that
              process stops.  The branch is “frozen” for
              final testing right before a release.
The branch is tagged and released.
              When testing is complete,
              /branches/1.0 is copied to
              /tags/1.0.0 as a reference
              snapshot.  The tag is packaged and released to
              customers.
The branch is maintained over time.
              While work continues on /trunk for
              version 2.0, bugfixes continue to be ported from
              /trunk to
              /branches/1.0.  When enough
              bugfixes have accumulated, management may decide to do a
              1.0.1 release: /branches/1.0 is
              copied to /tags/1.0.1, and the tag
              is packaged and released.
This entire process repeats as the software matures: when the 2.0 work is complete, a new 2.0 release branch is created, tested, tagged, and eventually released. After some years, the repository ends up with a number of release branches in “maintenance” mode, and a number of tags representing final shipped versions.
A feature branch is the sort of
          branch that's been the dominant example in this chapter, the
          one you've been working on while Sally continues to work on
          /trunk.  It's a temporary branch
          created to work on a complex change without interfering with
          the stability of /trunk.  Unlike
          release branches (which may need to be supported forever),
          feature branches are born, used for a while, merged back to
          the trunk, then ultimately deleted.  They have a finite span
          of usefulness.
Again, project policies vary widely concerning exactly
          when it's appropriate to create a feature branch.  Some
          projects never use feature branches at all: commits to
          /trunk are a free-for-all.  The
          advantage to this system is that it's simple—nobody
          needs to learn about branching or merging.  The disadvantage
          is that the trunk code is often unstable or unusable.  Other
          projects use branches to an extreme: no change is
          ever committed to the trunk directly.
          Even the most trivial changes are created on a short-lived
          branch, carefully reviewed and merged to the trunk.  Then
          the branch is deleted.  This system guarantees an
          exceptionally stable and usable trunk at all times, but at
          the cost of tremendous process overhead.
Most projects take a middle-of-the-road approach.  They
          commonly insist that /trunk compile and
          pass regression tests at all times.  A feature branch is
          only required when a change requires a large number of
          destabilizing commits.  A good rule of thumb is to ask this
          question: if the developer worked for days in isolation and
          then committed the large change all at once (so that
          /trunk were never destabilized), would
          it be too large a change to review?  If the answer to that
          question is “yes”, then the change should be
          developed on a feature branch.  As the developer commits
          incremental changes to the branch, they can be easily
          reviewed by peers.
Finally, there's the issue of how to best keep a feature branch in “sync” with the trunk as work progresses. As we mentioned earlier, there's a great risk to working on a branch for weeks or months; trunk changes may continue to pour in, to the point where the two lines of development differ so greatly that it may become a nightmare trying to merge the branch back to the trunk.
This situation is best avoided by regularly merging trunk changes to the branch. Make up a policy: once a week, merge the last week's worth of trunk changes to the branch. Take care when doing this; the merging needs to be hand-tracked to avoid the problem of repeated merges (as described in the section called “Tracking Merges Manually”). You'll need to write careful log messages detailing exactly which revision ranges have been merged already (as demonstrated in the section called “Merging a Whole Branch to Another”). It may sound intimidating, but it's actually pretty easy to do.
At some point, you'll be ready to merge the “synchronized” feature branch back to the trunk. To do this, begin by doing a final merge of the latest trunk changes to the branch. When that's done, the latest versions of branch and trunk will be absolutely identical except for your branch changes. So in this special case, you would merge by comparing the branch with the trunk:
$ cd trunk-working-copy
$ svn update
At revision 1910.
$ svn merge http://svn.example.com/repos/calc/trunk@1910 \
            http://svn.example.com/repos/calc/branches/mybranch@1910
U  real.c
U  integer.c
A  newdirectory
A  newdirectory/newfile
…
By comparing the HEAD revision of the
          trunk with the HEAD revision of the
          branch, you're defining a delta that describes only the
          changes you made to the branch; both lines of development
          already have all of the trunk changes.
Another way of thinking about this pattern is that your weekly sync of trunk to branch is analogous to running svn update in a working copy, while the final merge step is analogous to running svn commit from a working copy. After all, what else is a working copy but a very shallow private branch? It's a branch that's only capable of storing one change at a time.
[10] The Subversion project has plans, however, to someday implement an svnadmin obliterate command that would accomplish the task of permanently deleting information. In the meantime, see the section called “svndumpfilter” for a possible workaround.
[11] Because CVS doesn't version trees, it creates an
            Attic area within each repository
            directory as a way of remembering deleted files.