Sophie

Sophie

distrib > Mandriva > 2008.1 > x86_64 > media > main-release > by-pkgid > 1a3ab26f23e0518b4054a503057127e3 > files > 47

subversion-doc-1.4.6-5mdv2008.1.x86_64.rpm

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Basic Merging</title><link rel="stylesheet" href="styles.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Version Control with Subversion" /><link rel="up" href="svn.branchmerge.html" title="Chapter 4. Branching and Merging" /><link rel="prev" href="svn.branchmerge.using.html" title="Using Branches" /><link rel="next" href="svn.branchmerge.advanced.html" title="Advanced Merging" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Basic Merging</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="svn.branchmerge.using.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Branching and Merging</th><td width="20%" align="right"> <a accesskey="n" href="svn.branchmerge.advanced.html">Next</a></td></tr></table><hr /></div><div class="sect1" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="svn.branchmerge.basicmerging"></a>Basic Merging</h2></div></div></div><p>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 <em class="firstterm">trunk</em>, or main line of
      development.</p><p>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.</p><p>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
      <span class="emphasis"><em>too</em></span> far apart.  Remember that one of the
      problems with the “<span class="quote">crawl in a hole</span>” 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.</p><p>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
      “<span class="quote">copy</span>” 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 <em class="firstterm">merging</em>, and
      is performed using various invocations of the <span class="command"><strong>svn
      merge</strong></span> command.</p><p>In the examples that follow, we're assuming that both your
      Subversion client and server are running Subversion 1.5 (or
      later).  If either client or server is older than version 1.5,
      then things are more complicated: the system won't track changes
      automatically, and you'll have 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 <a class="xref" href="svn.branchmerge.advanced.html#svn.branchmerge.advanced.advancedsyntax" title="Merge Syntax: Full Disclosure">the section called “Merge Syntax:  Full Disclosure”</a>), and take
      special care to keep track of what's already been merged and
      what hasn't.  For this reason, we <span class="emphasis"><em>strongly</em></span>
      recommend making sure that your client and server are at least
      version 1.5 or later.</p><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.branchmerge.changesets"></a>Changesets</h3></div></div></div><p>Before we get too far in, we should warn you that there's
        going to be a lot of discussion of “<span class="quote">changes</span>” in
        the pages ahead.  A lot of people experienced with version
        control systems use the terms “<span class="quote">change</span>”
        and “<span class="quote">changeset</span>” interchangeably, and we should
        clarify what Subversion understands as
        a <em class="firstterm">changeset</em>.</p><p>Everyone seems to have a slightly different definition
        of “<span class="quote">changeset</span>”, or at least a different
        expectation of what it means for a version control system to
        have them.  For our purpose, 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.</p><p>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,
        “<span class="quote">this issue was fixed by revision 9238.</span>”.
        Somebody can then run <span class="command"><strong>svn log -r 9238</strong></span> to
        read about the exact changeset which fixed the bug, and run
        <span class="command"><strong>svn diff -c 9238</strong></span> to see the patch itself.
        And (as you'll see shortly)
        Subversion's <span class="command"><strong>merge</strong></span> command is able to use
        revision numbers.  You can merge specific changesets from one
        branch to another by naming them in the merge
        arguments: <span class="command"><strong>svn merge -c 9238</strong></span> would merge
        changeset #9238 into your working copy.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.branchemerge.basicmerging.stayinsync"></a>Keeping a Branch in Sync</h3></div></div></div><p>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 <code class="filename">/trunk</code>.  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 “<span class="quote">surprise</span>” conflicts when it comes time
        for you to fold your changes back into the trunk.</p><p>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 “<span class="quote">clean</span>”—that it has no local
        modifications.  Then simply run:</p><pre class="screen">
$ 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
</pre><p>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:</p><pre class="screen">
$ svn status
M  button.c
M  integer.c
</pre><p>At this point, the wise thing to do is look at the changes
        carefully with <span class="command"><strong>svn diff</strong></span>, then build and
        test your branch.  You might need to resolve some conflicts
        (just as you do with <span class="command"><strong>svn update</strong></span>), or
        possibly make some small edits to get things working properly.
        (Remember, just because there are
        no <span class="emphasis"><em>syntactic</em></span> conflicts doesn't mean there
        aren't any <span class="emphasis"><em>semantic</em></span> conflicts!)  If you
        encounter serious problems, you can always abort the local
        changes by running <span class="command"><strong>svn revert</strong></span> and start a
        long “<span class="quote">what's going on?</span>” discussion with your
        collaborators.  If things look good, however, then you can
        submit your changes into the repository:</p><pre class="screen">
$ svn commit -m "Merged /trunk to /my-calc-branch."
Sending        button.c
Sending        integer.c
Transmitting file data ..
Committed revision 357.
</pre><p>At this point, your private branch is now “<span class="quote">in
          sync</span>” 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.</p><div class="sidebar"><p class="title"><b>Why Not Use Patches Instead?</b></p><p>A question may be on your mind, especially if you're a
          Unix user: why bother to use <span class="command"><strong>svn merge</strong></span> at
          all?  Why not simply use the operating system's
          <span class="command"><strong>patch</strong></span> command to accomplish the same job?
          For example:</p><pre class="screen">
$ cd my-calc-branch
$ svn diff -r 341:HEAD http://svn.example.com/repos/calc/trunk &gt; patchfile
$ patch -p0  &lt; patchfile
Patching file integer.c using Plan A...
Hunk #1 succeeded at 147.
Hunk #2 succeeded at 164.
Hunk #3 succeeded at 241.
Hunk #4 succeeded at 249.
done
</pre><p>In this particular example, there really isn't much
          difference.  But <span class="command"><strong>svn merge</strong></span> has special
          abilities that surpass the <span class="command"><strong>patch</strong></span> program.
          The file format used by <span class="command"><strong>patch</strong></span> is quite
          limited; it's only able to tweak file contents.  There's no
          way to represent changes to <span class="emphasis"><em>trees</em></span>, such
          as the addition, removal, or renaming of files and
          directories.  Nor can the <span class="command"><strong>patch</strong></span> program
          notice changes to properties.  If Sally's change had,
          say, added a new directory, the output of <span class="command"><strong>svn
          diff</strong></span> wouldn't have mentioned it at
          all.  <span class="command"><strong>svn diff</strong></span> only outputs the limited
          patch-format, so there are some ideas it simply can't
          express.</p><p>The <span class="command"><strong>svn merge</strong></span> command, however, can
          express changes in tree structure and properties by directly
          applying them to your working copy.  Even more important,
          this command records the changes that have been duplicated
          to your branch, so that Subversion is aware of exactly which
          changes exist in each location (see
          <a class="xref" href="svn.branchmerge.basicmerging.html#svn.branchmerge.basicmerging.mergeinfo" title="Mergeinfo and Previews">the section called “Mergeinfo and Previews”</a>.)
          This is a critical feature that makes branch management
          usable; without it, users would have to manually keep notes
          on which sets of changes have or haven't been merged
          yet.</p></div><p>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!</p><pre class="screen">
$ svn merge http://svn.example.com/repos/calc/trunk
--- Merging r357 through r380 into '.':
U  integer.c
U  Makefile
A  README
</pre><p>Subversion knows which trunk changes you've already
        replicated to your branch, so it carefully only replicates
        those changes you don't yet have.  Once again, you'll have to
        build, test, and <span class="command"><strong>svn commit</strong></span> the local
        modifications to your branch.</p><p>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 trunk again, just as you've been
        doing all along:</p><pre class="screen">
$ 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.
</pre><p>Now, you use <span class="command"><strong>svn merge</strong></span> to replicate
        your branch changes back into the trunk.  To do this, you'll
        need an up-to-date working copy
        of <code class="filename">/trunk</code>.  You can do this by either
        doing an <span class="command"><strong>svn checkout</strong></span>, dredging up an old
        trunk working copy from somewhere on your disk, or by
        using <span class="command"><strong>svn switch</strong></span> (see
        <a class="xref" href="svn.branchmerge.switchwc.html" title="Traversing Branches">the section called “Traversing Branches”</a>.) However you get a
        trunk working copy, remember that it's a best practice to do
        your merge into a working copy that
        has <span class="emphasis"><em>no</em></span> local edits and has been recently
        updated.  If your working copy isn't “<span class="quote">clean</span>” in
        these ways, you can run into some conflict-related
        headaches.</p><p>Once you have a clean working copy of trunk,
        you're ready merge your branch back into it:</p><pre class="screen">
$ 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.
</pre><p>Congratulations, your branch has now been re-merged back
        into the main line of development.  Notice our use of
        the <code class="option">--reintegrate</code> option this time around.
        The option is needed because this sort of “<span class="quote">merge
        back</span>” is a different sort of work than what you've been
        doing up until now.  Previously, we had been
        asking <span class="command"><strong>svn merge</strong></span> to grab the “<span class="quote">next
        set</span>” of changes one branch and duplicate them to
        another 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.</p><p>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 <code class="option">--reintegrate</code> option, you're asking
        Subversion to carefully replicate <span class="emphasis"><em>only</em></span>
        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!)</p><p>Now that your branch is merged to trunk, you'll no longer
        need your branch.  You can do some basic housecleaning in the
        repository:</p><pre class="screen">
$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch
Committed revision 392.
</pre><p>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 your commits?  No need to worry.
        Remember that even though your branch is no longer visible in
        the <code class="filename">/branches</code> directory, its existence is
        still an immutable part of the repository's history.  A
        simple <span class="command"><strong>svn log</strong></span> command on
        the <code class="filename">/branches</code> URL will show the entire
        history of your branch.  Your branch can even be resurrected
        at some point, should you desire.  (See
        <a class="xref" href="svn.branchmerge.advanced.html#svn.branchmerge.advanced.resurrect" title="Resurrecting Deleted Items">the section called “Resurrecting Deleted Items”</a>.)</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.branchmerge.basicmerging.mergeinfo"></a>Mergeinfo and Previews</h3></div></div></div><p>The basic mechanism Subversion uses to track
        changesets—that is, which changes have been merged to
        which branches—is by recording data in properties.
        Specifically, merge data is tracked in
        the <code class="literal">svn:mergeinfo</code> property attached to
        files and directories.  (If you're not familiar with
        Subversion properties, now is the time to go skim over
        <a class="xref" href="svn.advanced.props.html" title="Properties">the section called “Properties”</a>.)</p><p>You can examine the property, just like any
        other:</p><pre class="screen">
$ cd my-calc-branch
$ svn propget svn:mergeinfo .
/trunk:341-390
</pre><p>It is <span class="emphasis"><em>not</em></span> recommended that you change
        the value of this property yourself, unless you really know
        what you're doing.  (An example of this comes up in
        <a class="xref" href="svn.branchmerge.advanced.html#svn.branchmerge.advanced.blockchanges" title="Blocking Changes">the section called “Blocking Changes”</a>.)  In
        general, this property is automatically maintained by
        Subversion whenever you run <span class="command"><strong>svn merge</strong></span>, and
        its value indicates which changes have already been replicated
        into a particular directory.</p><p>As we saw earlier, there's also a subcommand <span class="command"><strong>svn
        mergeinfo</strong></span>, which can be 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 the next set of changes that <span class="command"><strong>svn
        merge</strong></span> will replicate to your branch.</p><pre class="screen">
$ svn mergeinfo .
Path: .
Source path: /trunk
Merged ranges: r341:390
Eligible ranges: r391:395
</pre><p>The <span class="command"><strong>svn mergeinfo</strong></span> command, by default,
        looks back at the history of the thing you're querying and
        tries to make a sane guess about the “<span class="quote">source</span>” you
        want to be copying changes from.  In our prior example,
        because we're querying our branch working copy, the command
        assumes we're interested in receiving changes
        from <code class="filename">/trunk</code> (since that's where our
        branch was originally copied from.)  However, if another
        coworker had a different branch going on that we wanted to
        merge changes from, we could have this command tell us about
        eligible changesets from that source too:</p><pre class="screen">
$ svn mergeinfo --from-source \
http://svn.example.com/repos/calc/branches/other-branch  .
Path: .
Source path: /branches/other-branch
Merged ranges:
Eligible ranges: r360:364
</pre><p>Another way to get a more precise preview of a merge
        operation is to use the <code class="option">--dry-run</code>
        option.</p><pre class="screen">
$ svn merge http://svn.example.com/repos/calc/trunk --dry-run
U  integer.c

$ svn status
#  nothing printed, working copy is still unchanged.
</pre><p>The <code class="option">--dry-run</code> option doesn't actually
        apply any local changes to the working copy.  It only shows
        status codes that <span class="emphasis"><em>would</em></span> be printed in a
        real merge.  It's useful for getting a “<span class="quote">high
        level</span>” preview of the potential merge, for those times
        when running <span class="command"><strong>svn diff</strong></span> gives too much
        detail.</p><p>Of course, the best way to preview a merge operation is to
        just do it!  Remember, running <span class="command"><strong>svn merge</strong></span>
        isn't an inherently risky thing; if you don't like the
        results, simply <span class="command"><strong>svn revert -R</strong></span> the changes
        from your working copy and retry the command with different
        options.  The merge isn't final until you
        actually <span class="command"><strong>svn commit</strong></span> the results.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Tip</h3><p>While it's perfectly fine to experiment with merges by
          running <span class="command"><strong>svn merge</strong></span> and <span class="command"><strong>svn
          revert</strong></span> over and over, you may run into some
          annoying (but easily bypassed) roadblocks.  For example, if
          the merge operation adds a new file (i.e. schedules it for
          addition), then <span class="command"><strong>svn revert</strong></span> won't actually
          remove the file; it simply unschedules the addition.  You're
          left with an unversioned file.  If you then attempt to run
          the merge again, you may get conflicts due to the
          unversioned file “<span class="quote">being in the way</span>”.  Solution?
          After performing a revert, be sure to clean up the working
          copy and remove unversioned files and directories.  The
          output of <span class="command"><strong>svn status</strong></span> should be as clean
          (read: empty) as possible!</p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="svn.branchmerge.using.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="svn.branchmerge.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="svn.branchmerge.advanced.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Using Branches </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Advanced Merging</td></tr></table></div></body></html>