Now you and Sally are working on parallel branches of the project: you're working on a private branch, and Sally is working on the trunk, or main line of development.
For projects that have a large number of contributors, it's common for most people to have working copies of the trunk. Whenever someone needs to make a long-running change that is likely to disrupt the trunk, a standard procedure is to create a private branch and commit changes there until all the work is complete.
So, the good news is that you and Sally aren't interfering with each other. The bad news is that it's very easy to drift too far apart. Remember that one of the problems with the “crawl in a hole” strategy is that by the time you're finished with your branch, it may be near-impossible to merge your changes back into the trunk without a huge number of conflicts.
Instead, you and Sally might continue to share changes as you work. It's up to you to decide which changes are worth sharing; Subversion gives you the ability to selectively “copy” changes between branches. And when you're completely finished with your branch, your entire set of branch changes can be copied back into the trunk. In Subversion terminology, the general act of replicating changes from one branch to another is called merging, and it is performed using various invocations of the svn merge subcommand.
In the examples that follow, we're assuming that both your Subversion client and server are running Subversion 1.7 (or later). If either client or server is older than version 1.5, things are more complicated: the system won't track changes automatically, forcing you to use painful manual methods to achieve similar results. That is, you'll always need to use the detailed merge syntax to specify specific ranges of revisions to replicate (see the section called “Merge Syntax: Full Disclosure” later in this chapter), and take special care to keep track of what's already been merged and what hasn't. For this reason, we strongly recommend that you make sure your client and server are at least at version 1.5.
Before we proceed further, we should warn you that there's a lot of discussion of “changes” in the pages ahead. A lot of people experienced with version control systems use the terms “change” and “changeset” interchangeably, and we should clarify what Subversion understands as a changeset.
Everyone seems to have a slightly different definition of changeset, or at least a different expectation of what it means for a version control system to have one. For our purposes, let's say that a changeset is just a collection of changes with a unique name. The changes might include textual edits to file contents, modifications to tree structure, or tweaks to metadata. In more common speak, a changeset is just a patch with a name you can refer to.
In Subversion, a global revision
        number N names a tree in the
        repository: it's the way the repository looked after the
        Nth commit.  It's also the name of
        an implicit changeset: if you compare
        tree N with
        tree N-1, you can derive the exact
        patch that was committed.  For this reason, it's easy to think
        of revision N as not just a tree,
        but a changeset as well.  If you use an issue tracker to
        manage bugs, you can use the revision numbers to refer to
        particular patches that fix bugs—for example,
        “this issue was fixed by r9238.” Somebody
        can then run svn log -r 9238 to read about
        the exact changeset that fixed the bug, and run
        svn diff -c 9238 to see the patch itself.
        And (as you'll see shortly)
        Subversion's svn merge command is able to use
        revision numbers.  You can merge specific changesets from one
        branch to another by naming them in the merge
        arguments: passing -c 9238
        to svn merge would merge changeset r9238
        into your working copy.
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 continue 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.  This is done
        by performing a sync merge—a
        merge operation designed to bring your branch up to date with
        any changes made to its ancestral parent branch since your
        branch was created.
| ![[Tip]](images/tip.png)  | Tip | 
|---|---|
| Frequently keeping your branch in sync with the main development line helps prevent “surprise” conflicts when the time comes for you to fold your changes back into the trunk. | 
Subversion is aware of the history of your branch and knows when it split away from the trunk. To perform a sync merge, 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 ^/calc/trunk --- Merging r345 through r356 into '.': U button.c U integer.c --- Recording mergeinfo for merge of r345 through r356 into '.': U . $
This basic syntax—svn merge
        —tells
        Subversion to merge all changes which have not been previously
        merged from the URL to the current working directory (which is
        typically the root of your working copy).  Notice that we're
        using the caret (URL^)
        syntax[26] to avoid having to type out the
        entire /trunk URL.  Also note
        the “Recording mergeinfo for merge…”
        notification.  This tells you that the merge is updating
        the svn:mergeinfo property. We'll discuss
        both this property and these notifications later in this
        chapter, in
        the section called “Mergeinfo and Previews”.
After running the prior example, 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 . 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.  Notice that the current working directory
        (“.”) has also been
        modified; svn diff will show that
        its svn:mergeinfo property has been either
        created or modified.  This is important merge-related metadata
        that you should not touch, since it is
        needed by future svn merge commands.
        (We'll learn more about this metadata later in the
        chapter.)
After performing the merge, you might also 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 . -R (which
        will undo all local modifications) and starting a
        long “what's going on?” discussion with your
        collaborators.  If things look good, however, you can
        submit these changes into the repository:
$ svn commit -m "Merged latest trunk changes to my-calc-branch." Sending . 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 want to replicate the latest trunk changes to your branch and bring yourself in sync. Just run the same merge command again!
$ svn merge ^/calc/trunk svn: E195020: Cannot merge into mixed-revision working copy [357:378]; try up\ dating first $
Well that was unexpected!  After making changes to your
        branch over the past week you now find yourself with a working
        copy that contains a mixture of revisions (see
        the section called “Mixed-revision working copies”).  With the
        release of Subversion 1.7 the svn merge
        subcommand disables merges into mixed-revision working copies
        by default.  Without going into too much detail, this is
        because of limitations in the way merges are tracked by the
        svn:mergeinfo property (see
        the section called “Mergeinfo and Previews” for
        details).  These limitations mean that merges into
        mixed-revision working copies can result in unexpected text
        and tree conflicts.[27]  We don't want any needless conflicts, so
        we update the working copy and then reattempt the
        merge.
$ svn up Updating '.': At revision 380. $ svn merge ^/calc/trunk --- Merging r357 through r380 into '.': U integer.c U Makefile A README --- Recording mergeinfo for merge of r357 through r380 into '.': U . $
Subversion knows which trunk changes you previously replicated to your branch, so it carefully replicates only those changes you don't yet have. And once again, you build, test, and svn commit the local modifications to your branch.
| ![[Tip]](images/tip.png)  | Tip | 
|---|---|
| Prior to Subversion 1.7, merges unconditionally updated all of the subtree mergeinfo under the target to describe the merge. For users with a lot of subtree mergeinfo this meant that relatively “simple” merges (e.g. one which applied a diff to only a single file) resulted in changes to every subtree with mergeinfo, even those that were not parents of the effected path(s). This caused some level of confusion and frustration. Subversion 1.7 addresses this problem by only updating the mergeinfo on subtrees which are parents of the paths modified by the merge (i.e. paths changed, added, or deleted by application of the difference, see the section called “Merge Syntax: Full Disclosure”). The one exception to this behavior regards the actual merge target; the merge target's mergeinfo is always updated to describe the merge, even if the applied difference made no changes. | 
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 into sync with the trunk again, just as you've been doing all along[28]:
$ svn merge ^/calc/trunk --- Merging r381 through r385 into '.': U button.c U README --- Recording mergeinfo for merge of r381 through r385 into '.': U . $ # build, test, ... $ svn commit -m "Final merge of trunk changes to my-calc-branch." Sending . Sending button.c Sending README Transmitting file data .. Committed revision 390.
Now, use svn merge with the
        --reintegrate option to replicate your branch
        changes back into the trunk.  You'll need a working copy
        of /trunk.  You can get one by doing
        an svn checkout, dredging up an old trunk
        working copy from somewhere on your disk, or
        using svn switch (see
        the section called “Traversing Branches”).  Your trunk
        working copy cannot have any local edits or contain a mixture
        of revisions (see
        the section called “Mixed-revision working copies”).  While
        these are typically best practices for merging anyway, they
        are required when using the
        --reintegrate option.
Once you have a clean working copy of the trunk, you're ready to merge your branch back into it:
$ pwd /home/user/calc-trunk $ svn update # (make sure the working copy is up to date) Updating '.': At revision 390. $ svn merge --reintegrate ^/calc/branches/my-calc-branch --- Merging differences between repository URLs into '.': U button.c U integer.c U Makefile --- Recording mergeinfo for merge between repository URLs into '.': U . $ # build, test, verify, ... $ svn commit -m "Merge my-calc-branch back into trunk!" Sending . Sending button.c Sending integer.c Sending Makefile Transmitting file data .. Committed revision 391.
Congratulations, your branch-specific changes have now
        been merged back into the main line of development.  Notice
        our use of the --reintegrate option this time
        around.  The option is critical for reintegrating changes from
        a branch back into its original line of
        development—don't forget it!  It's needed because this
        sort of “merge back” is a different sort of work
        than what you've done up until now.  Previously, we were
        asking svn merge to grab the “next
        set” of changes from one line of development (the
        trunk) and duplicate them to another (your branch).  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 are quite different.  Your feature
        branch is now a mishmash 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!)
Keep in mind that the --reintegrate
        option is quite specialized in contrast to the more general
        nature of most Subversion subcommand options.  It supports the
        use case described above, but has little applicability outside
        of that.  Because of this narrow focus, in addition to
        requiring an up-to-date working copy[29] with no mixed-revisions,
        it will not function in combination with most of the other
        svn merge options. You'll get an error if you
        use any non-global options but these: --accept,
        --dry-run, --diff3-cmd,
        --extensions, or --quiet.
Now that your private branch is merged to trunk, you may wish to remove it from the repository:
$ svn delete ^/calc/branches/my-calc-branch \
      -m "Remove my-calc-branch, reintegrated with trunk in r391."
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”).
Once a --reintegrate merge is done from
        branch to trunk, the branch is no longer usable for further
        work.  It's not able to correctly absorb new trunk changes,
        nor can it be properly reintegrated to trunk again.  For this
        reason, if you want to keep working on your feature branch, we
        recommend destroying it and then re-creating it from the
        trunk:
$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch \
      -m "Remove my-calc-branch, reintegrated with trunk in r391."
Committed revision 392.
$ svn copy http://svn.example.com/repos/calc/trunk \
           http://svn.example.com/repos/calc/branches/my-calc-branch
      -m "Recreate my-calc-branch from trunk@HEAD."
Committed revision 393.
        There is another way of making the branch usable again after reintegration, without deleting the branch. See the section called “Keeping a Reintegrated Branch Alive”.
The basic mechanism Subversion uses to track
        changesets—that is, which changes have been merged to
        which branches—is by recording data in versioned
        properties.  Specifically, merge data is tracked in
        the svn:mergeinfo property attached to
        files and directories.  (If you're not familiar with
        Subversion properties, see the section called “Properties”.)
You can examine the property, just like any other:
$ cd my-calc-branch $ svn propget svn:mergeinfo . /trunk:341-390 $
| ![[Warning]](images/warning.png)  | Warning | 
|---|---|
| While it is possible to
          modify  | 
| ![[Tip]](images/tip.png)  | Tip | 
|---|---|
| The amount of  | 
The svn:mergeinfo property is
        automatically maintained by Subversion whenever you
        run svn merge.  Its value indicates which
        changes made to a given path have been replicated into the
        directory in question.  In our previous example, the path
        which is the source of the merged changes is
        /trunk and the directory which has
        received the changes is
        /branches/my-calc-branch.
        Earlier versions of Subversion maintained the
        svn:mergeinfo property silently. You could
        still detect the changes, after a merge completed, with the
        svn diff or svn status
        subcommands, but the merge itself gave no indication when it
        changed the svn:mergeinfo property. This is no
        longer true in Subversion 1.7, which has several new notifications
        to alert you when a merge updates the
        svn:mergeinfo property. These notifications
        all begin with “--- Recording mergeinfo for”
        and appear at the end of the merge.  Unlike other merge
        notifications, these don't describe the application of a
        difference to a working copy
        (see the section called “Merge Syntax:  Full Disclosure”),
        but instead describe "housekeeping" changes made to keep
        track of what was merged.
Subversion also provides a subcommand, svn mergeinfo, which is helpful in seeing not only which changesets a directory has absorbed, but also which changesets it's still eligible to receive. This gives a sort of preview of which changes a subsequent svn merge operation would replicate to your branch.
$ cd my-calc-branch # Which changes have already been merged from trunk to branch? $ svn mergeinfo ^/calc/trunk r341 r342 r343 … r388 r389 r390 # Which changes are still eligible to merge from trunk to branch? $ svn mergeinfo ^/calc/trunk --show-revs eligible r391 r392 r393 r394 r395 $
The svn mergeinfo command requires
        a “source” URL (where the changes come
        from), and takes an optional “target” URL (where
        the changes merge to).  If no target URL is given,
        it assumes that the current working directory is the
        target.  In the prior example, because we're querying our
        branch working copy, the command assumes we're interested in
        receiving changes to /branches/mybranch
        from the specified trunk URL.
With the release of Subversion 1.7, the
        svn mergeinfo subcommand can also account for
        subtree mergeinfo and non-inheritable mergeinfo.  It accounts for
        subtree mergeinfo by use of the --recursive or
        --depth options, while non-inheritable mergeinfo
        is considered by default.
Let's say we have a branch with both subtree and non-inheritable mergeinfo:
$ svn propget svn:mergeinfo --recursive -v
# Non-inheritable mergeinfo
Properties on '.':
  svn:mergeinfo
    /trunk:651-652,758*
# Subtree mergeinfo
Properties on 'doc/INSTALL':
  svn:mergeinfo
    /trunk/doc/INSTALL:651-652,958,1060
        From the above mergeinfo we see that r758 has only been
        merged into the root of the branch, but not any of the root's
        children.  We also see that both r958 and r1060 have been
        merged only to the doc/INSTALL file.
        When we use svn mergeinfo with the
        --recursive option to see what has been merged
        from ^/trunk to this branch, we see two
        revisions are flagged with the * marker:
$ svn mergeinfo --show-revs=merged ^/trunk . --recursive 651 652 758* 958* 1060
The * indicates revisions that are only
        partially merged to the target in question
        (the meaning is the same if we are checking for eligible
        revisions).  What this means in this example is that if we tried
        to merge r758 or r958 from ^/trunk then more
        changes would result. Likewise, because r1060 is
        not flagged with a *,
        we know that it only affects doc/INSTALL
        and that trying to merge it would have no result.[30]
Another way to get a more precise preview of a merge
        operation is to use the --dry-run
        option:
$ svn merge ^/calc/trunk --dry-run --- Merging r391 through r395 into 'branch': U integer.c $ svn status # nothing printed, working copy is still unchanged.
The --dry-run option doesn't actually
        apply any local changes to the working copy.  It shows only
        status codes that would be printed in a
        real merge.  It's useful for getting a “high-level”
        preview of the potential merge, for those times
        when running svn diff gives too much
        detail.
| ![[Tip]](images/tip.png)  | Tip | 
|---|---|
| After performing a merge operation, but before
          committing the results of the merge, you can
          use  | 
Of course, the best way to preview a merge operation is to
        just do it!  Remember, running svn merge
        isn't an inherently risky thing (unless you've made local
        modifications to your working copy—but we already
        stressed that you shouldn't merge into such an
        environment).  If you don't like the results of the merge,
        simply run svn revert . -R to revert
        the changes from your working copy and retry the command with
        different options.  The merge isn't final until you
        actually svn commit the results.
An extremely 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.  (You can do this by
        specifying --revision 303:302, or by an
        equivalent --change -303.)
$ svn merge -c -303 ^/calc/trunk --- Reverse-merging r303 into 'integer.c': U integer.c --- Recording mergeinfo for reverse merge of r303 into 'integer.c': U A-branch $ svn status M . 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.
As we mentioned earlier, one way to think about a
        repository revision is as a specific changeset.  By using the
        -r option, you can ask svn
        merge to apply a changeset, or a whole range of
        changesets, to your working copy.  In our case of undoing a
        change, we're asking svn merge to apply
        changeset r303 to our working copy
        backward.
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, she'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 the HEAD revision.  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 that 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.[31]
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 is defined by a specific coordinate pair. (Remember the “peg revision” syntax—foo.c@224—mentioned back in the section called “Peg and Operative Revisions”.)
First, you might 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 that used to contain your deleted item.  The
        --verbose (-v) 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 -v … ------------------------------------------------------------------------ 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 already
        discussed how to undo changes in
        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 90 files were changed in revision
        808?
A second, more targeted strategy is not to use svn merge at all, but rather to use the svn copy command. Simply copy the exact revision and path “coordinate pair” from the repository to your working copy:
$ svn copy ^/calc/trunk/real.c@807 ./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.  This is usually
        considered a good and useful thing.  If, however, you wanted
        to resurrect the file without
        maintaining a historical link to the old file, this technique
        works just as well:
$ svn cat ^/calc/trunk/real.c@807 > ./real.c $ svn add real.c A real.c $ svn commit -m "Re-created real.c from revision 807." Adding real.c Transmitting file data . Committed revision 1390.
Although our example shows us resurrecting a file, note that these same techniques work just as well for resurrecting deleted directories. Also note that a resurrection doesn't have to happen in your working copy—it can happen entirely in the repository:
$ svn copy ^/calc/trunk/real.c@807 ^/calc/trunk/ \
      -m "Resurrect real.c from revision 807."
Committed revision 1390.
$ svn update
Updating '.':
A    real.c
Updated to revision 1390.
        [26] This was introduced in svn 1.6.
[27] The svn
        merge subcommand
        option --allow-mixed-revisions allows you to
        override this prohibition, but you should only do so if you
        understand the ramifications and have a good reason for
        it.
[28] With Subversion 1.7 you don't absolutely have to do all your sync merges to the root of your branch as we do in this example. If your branch is effectively synced via a series of subtree merges then the reintegrate will work, but ask yourself, if the branch is effectively synced, then why are you doing subtree merges? Doing so is almost always needlessly complex.
[29] Reintegrate merges are allowed if the target is a shallow checkout (see the section called “Sparse Directories”) but any paths affected by the diff which are “missing” due to the sparse working copy will be skipped, probably not what you intended!
[30] This is often termed an “inoperative” merge. Though in this example the merge of r1060 would do something: It would update the mergeinfo on the root of the branch, but it would be inoperative in the sense that no diff would be applied.
[31] The Subversion project has plans, however, to someday implement a command that would accomplish the task of permanently deleting information. In the meantime, see the section called “svndumpfilter” for a possible workaround.