[svnbook commit] r2899 - trunk/src/en/book

sussman noreply at red-bean.com
Thu Dec 6 22:56:41 CST 2007


Author: sussman
Date: Thu Dec  6 22:56:38 2007
New Revision: 2899

Log:
Hack chapter 4 into a million pieces, scatter on floor, attempt to reassemble.

* src/en/book/ch04-branching-and-merging.xml:  slice and dice, add TODOs.

* src/en/book/ch02-basic-usage.xml:  update some xref tags.



Modified:
   trunk/src/en/book/ch02-basic-usage.xml
   trunk/src/en/book/ch04-branching-and-merging.xml

Modified: trunk/src/en/book/ch02-basic-usage.xml
==============================================================================
--- trunk/src/en/book/ch02-basic-usage.xml	(original)
+++ trunk/src/en/book/ch02-basic-usage.xml	Thu Dec  6 22:56:38 2007
@@ -569,7 +569,7 @@
               back anything you delete by checking out (or updating
               your working copy to) a revision earlier than the one in
               which you deleted it. Also see
-              <xref linkend="svn.branchmerge.commonuses.resurrect"/>.
+              <xref linkend="svn.branchmerge.advanced.resurrect"/>.
             </para></footnote></para>
           </listitem>
         </varlistentry>
@@ -1864,7 +1864,7 @@
           committed changes, but this won't work as you can't commit
           changes that you obtain from backdating a working copy if
           the changed files have newer revisions.  See <xref
-          linkend="svn.branchmerge.commonuses.resurrect"/> for a
+          linkend="svn.branchmerge.advanced.resurrect"/> for a
           description of how to <quote>undo</quote> a commit.</para>
       </tip>
 

Modified: trunk/src/en/book/ch04-branching-and-merging.xml
==============================================================================
--- trunk/src/en/book/ch04-branching-and-merging.xml	(original)
+++ trunk/src/en/book/ch04-branching-and-merging.xml	Thu Dec  6 22:56:38 2007
@@ -142,8 +142,8 @@
       development, in the repository.  This allows you to save your
       half-broken work frequently without interfering with others, yet
       you can still selectively share information with your
-      collaborators.  You'll see exactly how this works later
-      on.</para>
+      collaborators.  You'll see exactly how this works as we go.
+      </para>
 
     <!-- =============================================================== -->
     <sect2 id="svn.branchmerge.using.create">
@@ -165,57 +165,11 @@
         begins its life as a copy of
         <filename>/calc/trunk</filename>.</para>
 
-      <para>There are two different ways to make a copy.  We'll
-        demonstrate the messy way first, just to make the concept
-        clear.  To begin, check out a working copy of the project's
-        root directory, <filename>/calc</filename>:</para>
-
-      <screen>
-$ svn checkout http://svn.example.com/repos/calc bigwc
-A  bigwc/trunk/
-A  bigwc/trunk/Makefile
-A  bigwc/trunk/integer.c
-A  bigwc/trunk/button.c
-A  bigwc/branches/
-Checked out revision 340.
-</screen>
-
-      <para>Making a copy is now simply a matter of passing two
-        working-copy paths to the <command>svn copy</command>
-        command:</para>
-
-      <screen>
-$ cd bigwc
-$ svn copy trunk branches/my-calc-branch
-$ svn status
-A  +   branches/my-calc-branch
-</screen>
-
-      <para>In this case, the <command>svn copy</command> command
-        recursively copies the <filename>trunk</filename> working
-        directory to a new working directory,
-        <filename>branches/my-calc-branch</filename>.  As you can see
-        from the <command>svn status</command> command, the new
-        directory is now scheduled for addition to the repository.
-        But also notice the <quote>+</quote> sign next to the letter
-        A.  This indicates that the scheduled addition is a
-        <emphasis>copy</emphasis> of something, not something new.
-        When you commit your changes, Subversion will create
-        <filename>/calc/branches/my-calc-branch</filename> in the
-        repository by copying <filename>/calc/trunk</filename>, rather
-        than resending all of the working copy data over the
-        network:</para>
-
-      <screen>
-$ svn commit -m "Creating a private branch of /calc/trunk."
-Adding         branches/my-calc-branch
-Committed revision 341.
-</screen>
-
-      <para>And now here's the easier method of creating a branch,
-        which we should have told you about in the first
-        place: <command>svn copy</command> is able to operate directly
-        on two URLs.</para>
+      <para>At this point, you've probably seen <command>svn
+        copy</command> used to copy one file to another within a
+        working copy.  But it can also be used to do
+        a <quote>remote</quote> copy entirely within the repository.
+        Just copy one URL to another:</para>
 
       <screen>
 $ svn copy http://svn.example.com/repos/calc/trunk \
@@ -225,25 +179,27 @@
 Committed revision 341.
 </screen>
 
-      <para>From the repository's point of view, there's really no
-        difference between these two methods.  Both procedures create
-        a new directory in revision 341, and the new directory is a
-        copy of <filename>/calc/trunk</filename>.  This is shown in
-        <xref linkend="svn.branchmerge.using.create.dia-1"/>.  Notice
-        that the second method, however, performs an
-        <emphasis>immediate</emphasis> commit in constant time.
-
+      <para>This command causes a near-instantaneous commit in the
+        repository, creating a new directory in revision 341.  The new
+        directory is a copy of <filename>/calc/trunk</filename>.  This
+        is shown in
+        <xref linkend="svn.branchmerge.using.create.dia-1"/>.
         <footnote>
         <para>Subversion does not support copying between different
         repositories.  When using URLs with <command>svn
         copy</command> or <command>svn move</command>, you can only
         copy items within the same repository.</para> 
         </footnote>
-        
-        It's an easier procedure, because it doesn't require you to
-        check out a large portion of the repository.  In fact, this
-        technique doesn't even require you to have a working copy at
-        all.  This is the way most users create branches.</para>
+
+        While it's also possible to create a branch by
+        using <command>svn copy</command> to duplicate a directory
+        within the working copy, this technique isn't recommended.  It
+        can be quite slow, in fact!  Copying a directory on the
+        client-side is a linear-time operation, in that it actually
+        has to duplicate every file and subdirectory on local disk.
+        Copying a directory on the server, however, is a constant-time
+        operation, and it's the way most people create
+        branches.</para>
 
       <figure id="svn.branchmerge.using.create.dia-1">
         <title>Repository with new copy</title>
@@ -258,12 +214,12 @@
           repository growing huge—Subversion doesn't actually
           duplicate any data.  Instead, it creates a new directory
           entry that points to an <emphasis>existing</emphasis> tree.
-          If you're a Unix user, this is the same concept as a
-          hard-link.  As further changes are made to files and
-          directories beneath the copied directory, Subversion
-          continues to employ this hard-link concept where it can.  It
-          only duplicates data when it is necessary to disambiguate
-          different versions of objects.</para>
+          If you're an experience Unix user, you'll recognize this as
+          the same concept behind a hard-link.  As further changes are
+          made to files and directories beneath the copied directory,
+          Subversion continues to employ this hard-link concept where
+          it can.  It only duplicates data when it is necessary to
+          disambiguate different versions of objects.</para>
 
         <para>This is why you'll often hear Subversion users talk
           about <quote>cheap copies</quote>.  It doesn't matter how
@@ -434,7 +390,7 @@
 
     <!-- =============================================================== -->
     <sect2 id="svn.branchmerge.using.concepts">
-      <title>The Key Concepts Behind Branches</title> 
+      <title>The Key Concepts Behind Branching</title> 
 
       <para>There are two important lessons that you should remember
         from this section.  First, Subversion has no internal concept
@@ -444,13 +400,18 @@
         attach that meaning to it.  You may think of the directory
         differently, or treat it differently, but to Subversion it's
         just an ordinary directory that happens to carry some extra
-        historical information.  Second, because of this copy
-        mechanism, Subversion's branches exist as <emphasis>normal
-        filesystem directories</emphasis> in the repository.  This is
-        different from other version control systems, where branches
-        are typically defined by adding
+        historical information.</para>
+
+      <para>Second, because of this copy mechanism, Subversion's
+        branches exist as <emphasis>normal filesystem
+        directories</emphasis> in the repository.  This is different
+        from other version control systems, where branches are
+        typically defined by adding
         extra-dimensional <quote>labels</quote> to collections of
-        files.</para>
+        files.  The location of your branch directory doesn't matter
+        to Subversion.  Most teams follow a convention of putting all
+        branches into a <filename>/branches</filename> directory, but
+        you're free to invent any policy you wish.</para>
 
     </sect2>
 
@@ -459,8 +420,8 @@
   <!-- ================================================================= -->
   <!-- ================================================================= -->
   <!-- ================================================================= -->
-  <sect1 id="svn.branchmerge.copychanges">
-    <title>Copying Changes Between Branches</title>
+  <sect1 id="svn.branchmerge.basicmerging">
+    <title>Basic Merging</title>
 
     <para>Now you and Sally are working on parallel branches of the
       project: you're working on a private branch, and Sally is
@@ -489,23 +450,22 @@
       completely finished with your branch, your entire set of branch
       changes can be copied back into the trunk.</para>
 
-
-    <!-- =============================================================== -->
-    <sect2 id="svn.branchmerge.copychanges.specific">
-      <title>Copying Specific Changes</title>
-
-
-      <para>In the previous section, we mentioned that both you and
-        Sally made changes to <filename>integer.c</filename> on
-        different branches.  If you look at Sally's log message for
-        revision 344, you can see that she fixed some spelling errors.
-        No doubt, your copy of the same file still has the same spelling
-        errors.  It's likely that your future changes to this file will
-        be affecting the same areas that have the spelling errors, so
-        you're in for some potential conflicts when you merge your
-        branch someday.  It's better, then, to receive Sally's change
-        now, <emphasis>before</emphasis> you start working too heavily
-        in the same places.</para>
+    <para>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 <quote>manual</quote>
+      methods to achieve similar results.  (See
+      <xref linkend="svn.branchmerge.advanced"/>.)</para>
+
+  <!-- =============================================================== -->
+    <sect2 id="svn.branchemerge.basicmerging.stayinsync">
+      <title>Staying in Sync</title>
+
+      <para>###TODO:  show how to keep feature branch in sync with
+      trunk.  This is the first into to 'svn merge', so explain how
+      it creates edits in a working copy that can be either reverted
+      or committed.</para>
 
       <para>It's time to use the <command>svn merge</command> command.
         This command, it turns out, is a very close cousin to the
@@ -516,6 +476,160 @@
         diff</command> to show you the exact change made by Sally in
         revision 344:</para>
 
+      <sidebar>
+        <title>Why Not Use Patches Instead?</title>
+
+        <para>A question may be on your mind, especially if you're a
+          Unix user: why bother to use <command>svn merge</command> at
+          all?  Why not simply use the operating system's
+          <command>patch</command> command to accomplish the same job?
+          For example:</para>
+
+        <screen>
+$ cd my-calc-branch
+$ svn diff -r 341:HEAD http://svn.example.com/repos/calc/trunk > patchfile
+$ patch -p0  < 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
+</screen>
+
+        <para>In this particular case, yes, there really is no
+          difference.  But <command>svn merge</command> has special
+          abilities that surpass the <command>patch</command> program.
+          The file format used by <command>patch</command> is quite
+          limited; it's only able to tweak file contents.  There's no
+          way to represent changes to <emphasis>trees</emphasis>, such
+          as the addition, removal, or renaming of files and
+          directories.  Nor can the <command>patch</command> program
+          notice changes to properties.  If Sally's change had,
+          say, added a new directory, the output of <command>svn
+          diff</command> wouldn't have mentioned it at
+          all.  <command>svn diff</command> only outputs the limited
+          patch-format, so there are some ideas it simply can't
+          express.  The <command>svn merge</command> command, however,
+          can express changes in tree structure and properties by
+          directly applying them to your working copy.</para>
+
+      </sidebar>
+
+      <para>###TODO:  show how to merge back to trunk when done.</para>
+
+    </sect2>
+
+    <!-- =============================================================== -->
+    <sect2 id="svn.branchemerge.basicmerging.basicmergetracking">
+      <title>Basic Merge Tracking</title>
+
+      <para>###TODO: set expectations on what gets tracked and what
+      doesn't.</para>
+
+      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+      <sect3 id="svn.branchmerge.basicmerging.basicmergetracking.mergeinfo">
+        <title>Mergeinfo</title>
+
+        <para>###TODO: explain svn:mergeinfo prop and 'svn mergeinfo'
+          command, so users get a general sense of how the system is
+          tracking changes.</para>
+
+      </sect3>
+
+      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+      <sect3 id="svn.branchmerge.basicmerging.basicmergetracking.previews">
+        <title>Previewing Merges</title>
+
+        <para>It's a best practice to do your merge into a working
+          copy that has <emphasis>no</emphasis> local edits and has
+          been recently updated.  If your working copy
+          isn't <quote>clean</quote> in these ways, you can run into
+          some headaches.</para>
+
+        <para>Assuming your working copy is tidy, merging isn't a
+          particularly high-risk operation.  If you get the merge
+          wrong the first time, simply <command>svn revert</command>
+          the changes and try again.</para>
+
+        <para>If you've merged into a working copy that already has
+          local modifications, the changes applied by a merge will be
+          mixed with your pre-existing ones, and running
+          <command>svn revert</command> is no longer an option.  The
+          two sets of changes may be impossible to separate.</para>
+
+        <para>In cases like this, people take comfort in being able to
+          predict or examine merges before they happen.  One simple
+          way to do that is to run <command>svn diff</command> with
+          the same arguments you plan to pass to <command>svn
+          merge</command>, as we already showed in our first example
+          of merging.  Another method of previewing is to pass the
+          <option>--dry-run</option> option to the merge
+          command:</para>
+
+        <screen>
+$ svn merge --dry-run http://svn.example.com/repos/calc/trunk
+U  integer.c
+
+$ svn status
+#  nothing printed, working copy is still unchanged.
+</screen>
+
+        <para>The <option>--dry-run</option> option doesn't actually
+          apply any local changes to the working copy.  It only shows
+          status codes that <emphasis>would</emphasis> be printed in a
+          real merge.  It's useful for getting a <quote>high
+          level</quote> preview of the potential merge, for those
+          times when running <command>svn diff</command> gives too
+          much detail.</para>
+
+      </sect3>
+
+      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+      <sect3 id="svn.branchmerge.basicmerging.basicmergetracking.layered">
+        <title>Multi-Layered Merges</title>
+
+        <para>###TODO: explain how a merge can apply successive
+          patches, and that any intermediate conflicts *must* be
+          resolved (for now, at least.)</para>
+
+      </sect3>
+
+    </sect2>
+
+    </sect1>
+
+  <!-- ================================================================= -->
+  <!-- ================================================================= -->
+  <!-- ================================================================= -->
+  <sect1 id="svn.branchmerge.advanced">
+    <title>Advanced Merging</title>
+
+    <para>###TODO: Intro: talk about how and why advanced users can
+      pass specific revision numbers to 'svn merge'.</para>
+
+
+    <!-- =============================================================== -->
+    <sect2 id="svn.branchmerge.copychanges.specific">
+      <title>Copying Specific Changes</title>
+
+      <para>Let's go back in time and imagine that you haven't yet
+        merged your private branch back to the trunk. ... ### TODO:
+        explain why we'd want to cherrypick one change, and let's say
+        it's r344:</para>
+
+      <para>Assume you get word that Sally made an interesting change
+        to <filename>integer.c</filename> on the trunk.  ###TODO: blah
+        blah: If you look at Sally's log message for revision 344, you
+        can see that she fixed some spelling errors.  No doubt, your
+        copy of the same file still has the same spelling errors.
+        It's likely that your future changes to this file will be
+        affecting the same areas that have the spelling errors, so
+        you're in for some potential conflicts when you merge your
+        branch someday.  It's better, then, to receive Sally's change
+        now, <emphasis>before</emphasis> you start working too heavily
+        in the same places.</para>
+
       <screen>
 $ svn diff -c 344 http://svn.example.com/repos/calc/trunk
 
@@ -597,8 +711,8 @@
         between branches is commonly called
         <firstterm>porting</firstterm> changes.</para>
 
-      <para>When you commit the local modification, make sure your log
-        message mentions that you're porting a specific change from
+      <para>When you commit the local modification, it's a good
+        practice to mention that you're porting a specific change from
         one branch to another.  For example:</para>
 
       <screen>
@@ -608,48 +722,6 @@
 Committed revision 360.
 </screen>
 
-      <para>As you'll see in the next sections, this is a very
-        important <quote>best practice</quote> to follow.</para>
-
-      <sidebar>
-        <title>Why Not Use Patches Instead?</title>
-
-        <para>A question may be on your mind, especially if you're a
-          Unix user: why bother to use <command>svn merge</command> at
-          all?  Why not simply use the operating system's
-          <command>patch</command> command to accomplish the same job?
-          For example:</para>
-
-        <screen>
-$ svn diff -c 344 http://svn.example.com/repos/calc/trunk > patchfile
-$ patch -p0  < 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
-</screen>
-
-        <para>In this particular case, yes, there really is no
-          difference.  But <command>svn merge</command> has special
-          abilities that surpass the <command>patch</command> program.
-          The file format used by <command>patch</command> is quite
-          limited; it's only able to tweak file contents.  There's no
-          way to represent changes to <emphasis>trees</emphasis>, such
-          as the addition, removal, or renaming of files and
-          directories.  Nor can the <command>patch</command> program
-          notice changes to properties.  If Sally's change had,
-          say, added a new directory, the output of <command>svn
-          diff</command> wouldn't have mentioned it at
-          all.  <command>svn diff</command> only outputs the limited
-          patch-format, so there are some ideas it simply can't
-          express.  The <command>svn merge</command> command, however,
-          can express changes in tree structure and properties by
-          directly applying them to your working copy.</para>
-
-      </sidebar>
-
       <para>A word of warning: while <command>svn diff</command> and
         <command>svn merge</command> are very similar in concept, they
         do have different syntax in many cases.  Be sure to read about
@@ -667,7 +739,7 @@
         </listitem>
         <listitem>
           <para>You want to merge the changes in a specific file into
-            a file by the same name which exists in your current working 
+            a file by the same name which exists in your current working
             directory.</para>
         </listitem>
       </orderedlist>
@@ -693,10 +765,10 @@
     </sect2>
 
     <!-- =============================================================== -->
-    <sect2 id="svn.branchmerge.copychanges.keyconcept">
-      <title>The Key Concept Behind Merging</title>
+    <sect2 id="svn.branchmerge.advanced.advancedsyntax">
+      <title>Advanced Merge Syntax</title>
 
-      <para>You've now seen an example of the <command>svn
+      <para>You've now seen some examples of the <command>svn
           merge</command> command, and you're about to see several
           more.  If you're feeling confused about exactly how merging
           works, you're not alone.  Many users (especially those new
@@ -717,7 +789,27 @@
         two repository trees are compared, and the differences are
         applied to a working copy.</para>
 
-      <para>The command takes three arguments:</para>
+      <para>If you're using <command>svn merge</command> to do basic
+        copying of changes between branches, it will generally do the
+        right thing automatically.  For example, a command like</para>
+
+      <screen>
+$ svn merge http://svn.example.com/repos/calc/some-branch
+</screen>
+
+      <para>... will attempt to duplicate any changes made
+        on <filename>some-branch</filename> into your current working
+        directory, which is presumably a working copy that shares some
+        historical connection to the branch.  The command is smart
+        enough to only duplicate changes that your working copy
+        doesn't yet have.  If you repeat this command once a week, it
+        will only duplicate the <quote>newest</quote> branch changes
+        that happened since you last merged.</para>
+
+      <para>If you choose to use the <command>svn merge</command>
+        command in all its full glory by giving it specific revision
+        ranges to duplicate, then the command takes three main
+        arguments:</para>
 
       <orderedlist>
 
@@ -767,349 +859,254 @@
         how the working-copy argument is optional; if omitted, it
         defaults to the current directory.</para>
 
-
     </sect2>
 
     <!-- =============================================================== -->
-    <sect2 id="svn.branchmerge.copychanges.bestprac">
-      <title>Best Practices for Merging</title>
-
-      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-      <sect3 id="svn.branchmerge.copychanges.bestprac.track">
-        <title>Tracking Merges Manually</title>
-
-        <para>Merging changes sounds simple enough, but in practice it
-          can become a headache.  The problem is that if you
-          repeatedly merge changes from one branch to another, you
-          might accidentally merge the same change
-          <emphasis>twice</emphasis>.  When this happens, sometimes
-          things will work fine.  When patching a file, Subversion
-          typically notices if the file already has the change, and
-          does nothing.  But if the already-existing change has been
-          modified in any way, you'll get a conflict.</para>
-
-        <para>Ideally, your version control system should prevent the
-          double-application of changes to a branch.  It should
-          automatically remember which changes a branch has already
-          received, and be able to list them for you.  It should use
-          this information to help automate merges as much as
-          possible.</para>
-
-        <para>Unfortunately, Subversion is not such a system; it does
-          not yet record any information about merge operations.
-            <footnote><para>However, at the time of writing, this
-             feature is being worked on!</para></footnote>
-          When you commit local modifications, the repository has no
-          idea whether those changes came from running <command>svn
-          merge</command>, or from just hand-editing the files.</para>
-
-        <para>What does this mean to you, the user?  It means that
-          until the day Subversion grows this feature, you'll have to
-          track merge information yourself.  The best place to do this
-          is in the commit log-message.  As demonstrated in prior
-          examples, it's recommended that your log-message mention a
-          specific revision number (or range of revisions) that are
-          being merged into your branch.  Later on, you can
-          run <command>svn log</command> to review which changes your
-          branch already contains.  This will allow you to carefully
-          construct a subsequent <command>svn merge</command> command
-          that won't be redundant with previously ported
-          changes.</para>
-
-        <para>In the next section, we'll show some examples of this
-          technique in action.</para>
-
-      </sect3>
-
-      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-      <sect3 id="svn.branchmerge.copychanges.bestprac.preview">
-        <title>Previewing Merges</title>
-
-        <para>First, always remember to do your merge into a working
-          copy that has <emphasis>no</emphasis> local edits and has
-          been recently updated.  If your working copy
-          isn't <quote>clean</quote> in these ways, you can run into
-          some headaches.</para>
-
-        <para>Assuming your working copy is tidy, merging isn't a
-          particularly high-risk operation.  If you get the merge
-          wrong the first time, simply <command>svn revert</command>
-          the changes and try again.</para>
+    <sect2 id="svn.branchmerge.advanced.undo">
+      <title>Undoing Changes</title>
 
-        <para>If you've merged into a working copy that already has
-          local modifications, the changes applied by a merge will be
-          mixed with your pre-existing ones, and running
-          <command>svn revert</command> is no longer an option.  The
-          two sets of changes may be impossible to separate.</para>
+      <para>Another common use for <command>svn merge</command> is to
+        roll back a change that has already been committed.  Suppose
+        you're working away happily on a working copy of
+        <filename>/calc/trunk</filename>, and you discover that the
+        change made way back in revision 303, which changed
+        <filename>integer.c</filename>, is completely wrong.  It never
+        should have been committed.  You can use <command>svn
+        merge</command> to <quote>undo</quote> the change in your
+        working copy, and then commit the local modification to the
+        repository.  All you need to do is to specify a
+        <emphasis>reverse</emphasis> difference.  (You can do this by
+        specifying <option>--revision 303:302</option>, or by an
+        equivalent <option>--change -303</option>.)</para>
 
-        <para>In cases like this, people take comfort in being able to
-          predict or examine merges before they happen.  One simple
-          way to do that is to run <command>svn diff</command> with
-          the same arguments you plan to pass to <command>svn
-          merge</command>, as we already showed in our first example
-          of merging.  Another method of previewing is to pass the
-          <option>--dry-run</option> option to the merge
-          command:</para>
 
-        <screen>
-$ svn merge --dry-run -c 344 http://svn.example.com/repos/calc/trunk
+      <screen>
+$ svn merge -c -303 http://svn.example.com/repos/calc/trunk
 U  integer.c
 
 $ svn status
-#  nothing printed, working copy is still unchanged.
-</screen>
-
-        <para>The <option>--dry-run</option> option doesn't actually
-          apply any local changes to the working copy.  It only shows
-          status codes that <emphasis>would</emphasis> be printed in a
-          real merge.  It's useful for getting a <quote>high
-          level</quote> preview of the potential merge, for those
-          times when running <command>svn diff</command> gives too
-          much detail.</para>
+M  integer.c
 
-      </sect3>
+$ svn diff
+…
+# verify that the change is removed
+…
 
-      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-      <sect3 id="svn.branchmerge.copychanges.bestprac.merge">
-        <title>Merge Conflicts</title>
+$ svn commit -m "Undoing change committed in r303."
+Sending        integer.c
+Transmitting file data .
+Committed revision 350.
+</screen>
 
-        <para>Just like the <command>svn update</command> command,
-          <command>svn merge</command> applies changes to your working
-          copy.  And therefore it's also capable of creating
-          conflicts.  The conflicts produced by <command>svn
-          merge</command>, however, are sometimes different, and this
-          section explains those differences.</para>
+      <para>One way to think about a repository revision is as a
+        specific group of changes (some version control systems call
+        these <firstterm>changesets</firstterm>).  By using the
+        <option>-r</option> option, you can ask <command>svn
+        merge</command> to apply a changeset, or whole range of
+        changesets, to your working copy.  In our case of undoing a
+        change, we're asking <command>svn merge</command> to apply
+        changeset #303 to our working copy
+        <emphasis>backwards</emphasis>.</para>
 
-        <para>To begin with, assume that your working copy has no
-          local edits.  When you <command>svn update</command> to a
-          particular revision, the changes sent by the server will
-          always apply <quote>cleanly</quote> to your working copy.
-          The server produces the delta by comparing two trees: a
-          virtual snapshot of your working copy, and the revision tree
-          you're interested in.  Because the left-hand side of the
-          comparison is exactly equal to what you already have, the
-          delta is guaranteed to correctly convert your working copy
-          into the right-hand tree.</para>
-
-        <para>But <command>svn merge</command> has no such guarantees
-          and can be much more chaotic: the user can ask the server to
-          compare <emphasis>any</emphasis> two trees at all, even ones
-          that are unrelated to the working copy!  This means there's
-          large potential for human error.  Users will sometimes
-          compare the wrong two trees, creating a delta that doesn't
-          apply cleanly.  <command>svn merge</command> will do its
-          best to apply as much of the delta as possible, but some
-          parts may be impossible.  Just as the Unix
-          <command>patch</command> command sometimes complains about
-          <quote>failed hunks</quote>, <command>svn merge</command>
-          will complain about <quote>skipped targets</quote>:</para>
+      <sidebar>
+        <title>Subversion and Changesets</title>
 
-        <screen>
-$ svn merge -r 1288:1351 http://svn.example.com/repos/branch
-U  foo.c
-U  bar.c
-Skipped missing target: 'baz.c'
-U  glub.c
-C  glorb.h
+        <para>Everyone seems to have a slightly different definition
+          of <quote>changeset</quote>, or at least a different
+          expectation of what it means for a version control system to
+          have <quote>changeset features</quote>.  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.</para>
 
-$
-</screen>
+        <para>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 <quote>revision N</quote> 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,
+          <quote>this issue was fixed by revision 9238.</quote>.
+          Somebody can then run <command>svn log -r9238</command> to
+          read about the exact changeset which fixed the bug, and run
+          <command>svn diff -c 9238</command> to see the patch
+          itself.  And Subversion's <literal>merge</literal> command
+          also uses revision numbers.  You can merge specific changesets
+          from one branch to another by naming them in the merge
+          arguments: <command>svn merge -c 9238</command> would
+          merge changeset #9238 into your working copy.</para>
+      </sidebar>
 
-        <para>In the previous example it might be the case that
-          <filename>baz.c</filename> exists in both snapshots of the
-          branch being compared, and the resulting delta wants to
-          change the file's contents, but the file doesn't exist in
-          the working copy.  Whatever the case, the
-          <quote>skipped</quote> message means that the user is most
-          likely comparing the wrong two trees; they're the classic
-          sign of user error.  When this happens, it's easy to
-          recursively revert all the changes created by the merge
-          (<command>svn revert --recursive</command>), delete any
-          unversioned files or directories left behind after the
-          revert, and re-run <command>svn merge</command> with
-          different arguments.</para>
-
-        <para>Also notice that the previous example shows a conflict
-          happening on <filename>glorb.h</filename>.  We already
-          stated that the working copy has no local edits: how can a
-          conflict possibly happen?  Again, because the user can use
-          <command>svn merge</command> to define and apply any old
-          delta to the working copy, that delta may contain textual
-          changes that don't cleanly apply to a working file, even if
-          the file has no local modifications.</para>
+      <para>Keep in mind that rolling back a change like this is just
+        like any other <command>svn merge</command> operation, so you
+        should use <command>svn status</command> and <command>svn
+        diff</command> to confirm that your work is in the state you
+        want it to be in, and then use <command>svn commit</command>
+        to send the final version to the repository.  After
+        committing, this particular changeset is no longer reflected
+        in the <literal>HEAD</literal> revision.</para>
 
-        <para>Another small difference between <command>svn
-          update</command> and <command>svn merge</command> are the
-          names of the full-text files created when a conflict
-          happens.  In <xref linkend="svn.tour.cycle.resolve"/>, we saw
-          that an update produces files named
-          <filename>filename.mine</filename>,
-          <filename>filename.rOLDREV</filename>, and
-          <filename>filename.rNEWREV</filename>.  When <command>svn
-          merge</command> produces a conflict, though, it creates
-          three files named <filename>filename.working</filename>,
-          <filename>filename.left</filename>, and
-          <filename>filename.right</filename>.  In this case, the
-          terms <quote>left</quote> and <quote>right</quote> are
-          describing which side of the double-tree comparison the file
-          came from.  In any case, these differing names will help you
-          distinguish between conflicts that happened as a result of an
-          update versus ones that happened as a result of a
-          merge.</para>
+      <para>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
+        <filename>calc</filename> project between revisions 303 and
+        349, they'll still see the bad change, right?</para>
 
-      </sect3>
+      <para>Yes, that's true.  When we talk about
+        <quote>removing</quote> a change, we're really talking about
+        removing it from <literal>HEAD</literal>.  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 <literal>HEAD</literal> 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.
+        <footnote>
+          <para>The Subversion project has plans, however, to someday
+            implement a command that would accomplish the task of
+            permanently deleting information.  In the meantime, see
+            <xref linkend="svn.reposadmin.maint.tk.svndumpfilter"/>
+            for a possible workaround.</para>
+        </footnote>
+      </para>
 
-      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-      <sect3 id="svn.branchmerge.copychanges.bestprac.ancestry">
-        <title>Noticing or Ignoring Ancestry</title>
+    </sect2>
 
-        <para>When conversing with a Subversion developer, you might
-          very likely hear reference to the term
-          <firstterm>ancestry</firstterm>.  This word is used to
-          describe the relationship between two objects in a
-          repository: if they're related to each other, then one
-          object is said to be an ancestor of the other.</para>
-
-        <para>For example, suppose you commit revision 100, which
-          includes a change to a file <filename>foo.c</filename>.
-          Then <filename>foo.c at 99</filename> is an
-          <quote>ancestor</quote> of <filename>foo.c at 100</filename>.
-          On the other hand, suppose you commit the deletion of
-          <filename>foo.c</filename> in revision 101, and then add a
-          new file by the same name in revision 102.  In this case,
-          <filename>foo.c at 99</filename> and
-          <filename>foo.c at 102</filename> may appear to be related
-          (they have the same path), but in fact are completely
-          different objects in the repository.  They share no history
-          or <quote>ancestry</quote>.</para>
-
-        <para>The reason for bringing this up is to point out an
-          important difference between <command>svn diff</command> and
-          <command>svn merge</command>.  The former command ignores
-          ancestry, while the latter command is quite sensitive to it.
-          For example, if you asked <command>svn diff</command> to
-          compare revisions 99 and 102 of <filename>foo.c</filename>,
-          you would see line-based diffs; the <literal>diff</literal>
-          command is blindly comparing two paths.  But if you asked
-          <command>svn merge</command> to compare the same two objects,
-          it would notice that they're unrelated and first attempt to
-          delete the old file, then add the new file;  the output would
-          indicate a deletion followed by an add:</para>
+    <!-- =============================================================== -->
+    <sect2 id="svn.branchmerge.advanced.resurrect">
+      <title>Resurrecting Deleted Items</title>
 
-        <screen>
-D  foo.c
-A  foo.c
-</screen>
+      <para>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 <literal>HEAD</literal>
+        revision, but the object still exists in earlier revisions.
+        One of the most common questions new users ask is, <quote>How
+        do I get my old file or directory back?</quote>.</para>
 
-        <para>Most merges involve comparing trees that are ancestrally
-          related to one another, and therefore <command>svn
-          merge</command> defaults to this behavior.  Occasionally,
-          however, you may want the <literal>merge</literal> command
-          to compare two unrelated trees.  For example, you may have
-          imported two source-code trees representing different vendor
-          releases of a software project (see <xref
-          linkend="svn.advanced.vendorbr"/>).  If you asked
-          <command>svn merge</command> to compare the two trees, you'd
-          see the entire first tree being deleted, followed by an add
-          of the entire second tree!  In these situations, you'll want
-          <command>svn merge</command> to do a path-based comparison
-          only, ignoring any relations between files and directories.
-          Add the <option>--ignore-ancestry</option> option to your
-          merge command, and it will behave just like <command>svn
-          diff</command>.  (And conversely, the
-          <option>--notice-ancestry</option> option will cause
-          <command>svn diff</command> to behave like the
-          <literal>merge</literal> command.)</para>
+      <para>The first step is to define
+        exactly <emphasis role="bold">which</emphasis> 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.  (Remember the
+        <quote>peg revision</quote> syntax—foo.c at 224
+        —mentioned back in
+        <xref linkend="svn.advanced.pegrevs"/>.) </para>
 
-      </sect3>
+      <para>First, you might need to use <command>svn log</command> to
+        discover the exact coordinate pair you wish to resurrect.  A
+        good strategy is to run <command>svn log
+        --verbose</command> in a directory which used to contain your
+        deleted item.  The <option>--verbose (-v)</option> 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 <command>grep</command>, or
+        perhaps via an incremental search in an editor).</para>
 
-      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-      <sect3 id="svn.branchmerge.copychanges.bestprac.moves">
-        <title>Merges and Moves</title>
+      <screen>
+$ 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
 
-        <para>A common desire is to refactor source code, especially
-          in Java-based software projects.  Files and directories are
-          shuffled around and renamed, often causing great disruption
-          to everyone working on the project.  Sounds like a perfect
-          case to use a branch, doesn't it?  Just create a branch,
-          shuffle things around, then merge the branch back to the
-          trunk, right?</para>
-
-        <para>Alas, this scenario doesn't work so well right now, and
-          is considered one of Subversion's current weak spots.  The
-          problem is that Subversion's <command>update</command>
-          command isn't as robust as it should be, particularly when
-          dealing with copy and move operations.</para>
-
-        <para>When you use <command>svn copy</command> to duplicate a
-          file, the repository remembers where the new file came from,
-          but it fails to transmit that information to the client
-          which is running <command>svn update</command>
-          or <command>svn merge</command>.  Instead of telling the
-          client, <quote>Copy that file you already have to this new
-          location</quote>, it instead sends down an entirely new
-          file.  This can lead to problems, especially because the
-          same thing happens with renamed files.  A lesser-known fact
-          about Subversion is that it lacks <quote>true
-          renames</quote>—the <command>svn move</command>
-          command is nothing more than an aggregation of <command>svn
-          copy</command> and <command>svn delete</command>.</para>
+Added fast fourier transform functions to integer.c.
+Removed real.c because code now in double.c.
+…
+</screen>
 
-        <para>For example, suppose that while working on your private
-          branch, you rename <filename>integer.c</filename>
-          to <filename>whole.c</filename>.  Effectively you've created
-          a new file in your branch that is a copy of the original
-          file, and deleted the original file.  Meanwhile, back
-          on <filename>trunk</filename>, Sally has committed some
-          improvements to <filename>integer.c</filename>.  Now you
-          decide to merge your branch to the trunk:</para>
+      <para>In the example, we're assuming that you're looking for a
+        deleted file <filename>real.c</filename>.  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
+        <filename>/calc/trunk/real.c</filename> from revision
+        807.</para>
 
-        <screen>
-$ cd calc/trunk
+      <para>That was the hard part—the research.  Now that you
+        know what you want to restore, you have two different
+        choices.</para>
 
-$ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch
-D   integer.c
-A   whole.c
-</screen>
+      <para>One option is to use <command>svn merge</command> to apply
+        revision 808 <quote>in reverse</quote>.  (We've already
+        discussed how to undo changes, see
+        <xref linkend="svn.branchmerge.advanced.undo"/>.)  This
+        would have the effect of re-adding <filename>real.c</filename>
+        as a local modification.  The file would be scheduled for
+        addition, and after a commit, the file would again exist
+        in <literal>HEAD</literal>.</para>
 
-        <para>This doesn't look so bad at first glance, but it's also
-          probably not what you or Sally expected.  The merge
-          operation has deleted the latest version
-          of <filename>integer.c</filename> file (the one containing
-          Sally's latest changes), and blindly added your
-          new <filename>whole.c</filename> file—which is a
-          duplicate of the <emphasis>older</emphasis> version
-          of <filename>integer.c</filename>.  The net effect is that
-          merging your <quote>rename</quote> to the branch has removed
-          Sally's recent changes from the latest revision!</para>
-
-        <para>This isn't true data-loss; Sally's changes are still in
-          the repository's history, but it may not be immediately
-          obvious that this has happened.  The moral of this story is
-          that until Subversion improves, be very careful about
-          merging copies and renames from one branch to
-          another.</para>
+      <para>In this particular example, however, this is probably not
+        the best strategy.  Reverse-applying revision 808 would not
+        only schedule <filename>real.c</filename> for addition, but
+        the log message indicates that it would also undo certain
+        changes to <filename>integer.c</filename>, which you don't
+        want.  Certainly, you could reverse-merge revision 808 and
+        then <command>svn revert</command> the local modifications to
+        <filename>integer.c</filename>, but this technique doesn't
+        scale well.  What if there were 90 files changed in revision
+        808?</para>
 
-      </sect3>
+      <para>A second, more targeted strategy is not to use
+        <command>svn merge</command> at all, but rather the
+        <command>svn copy</command> command.  Simply copy the exact
+        revision and path <quote>coordinate pair</quote> from the
+        repository to your working copy:</para>
 
-    </sect2>
+      <screen>
+$ svn copy -r 807 \
+           http://svn.example.com/repos/calc/trunk/real.c ./real.c
 
+$ svn status
+A  +   real.c
 
-  </sect1>
+$ svn commit -m "Resurrected real.c from revision 807, /calc/trunk/real.c."
+Adding         real.c
+Transmitting file data .
+Committed revision 1390.
+</screen>
 
-  <!-- ================================================================= -->
-  <!-- ================================================================= -->
-  <!-- ================================================================= -->
-  <sect1 id="svn.branchmerge.commonuses">
-    <title>Common Use-Cases</title>
+      <para>The plus sign in the status output indicates that the item
+        isn't merely scheduled for addition, but scheduled for
+        addition <quote>with history</quote>.  Subversion remembers
+        where it was copied from.  In the future, running <command>svn
+        log</command> 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
+        <filename>real.c</filename> isn't really new; it's a direct
+        descendant of the original, deleted file.</para>
 
-    <para>There are many different uses for branching and <command>svn
-      merge</command>, and this section describes the most common ones
-      you're likely to run into.</para>
+      <para>Although our example shows us resurrecting a file, note
+        that these same techniques work just as well for resurrecting
+        deleted directories.</para>
+
+    </sect2>
 
     <!-- =============================================================== -->
-    <sect2 id="svn.branchmerge.commonuses.wholebr">
-      <title>Merging a Whole Branch to Another</title>
+    <sect2 id="svn.branchmerge.advanced.manual">
+      <title>Manually Merging a Branch</title>
+
+      <para>###TODO: if basic merge tracking isn't available (client
+        or server is older than 1.5), then here is the 'manual' method
+        for keeping a private branch in sync with trunk, and how to
+        merge it back into trunk:</para>
 
       <para>To complete our running example, we'll move forward in
         time.  Suppose several days have passed, and many changes have
@@ -1218,11 +1215,10 @@
         to your original feature or bug fix.  The repository's
         <literal>HEAD</literal> revision is now 480, and you're ready
         to do another merge from your private branch to the trunk.
-        But as discussed in <xref linkend="svn.branchmerge.copychanges.bestprac"/>, you
-        don't want to merge the changes you've already merged before;
-        you only want to merge everything <quote>new</quote> on your
-        branch since the last time you merged.  The trick is to figure
-        out what's new.</para>
+        But don't want to merge the changes you've already merged
+        before; you only want to merge everything <quote>new</quote>
+        on your branch since the last time you merged.  The trick is
+        to figure out what's new.</para>
 
       <para>The first step is to run <command>svn log</command> on the
         trunk, and look for a log message about the last time you
@@ -1274,453 +1270,470 @@
 
     </sect2>
 
-    <!-- =============================================================== -->
-    <sect2 id="svn.branchmerge.commonuses.undo">
-      <title>Undoing Changes</title>
-
-      <para>Another common use for <command>svn merge</command> is to
-        roll back a change that has already been committed.  Suppose
-        you're working away happily on a working copy of
-        <filename>/calc/trunk</filename>, and you discover that the
-        change made way back in revision 303, which changed
-        <filename>integer.c</filename>, is completely wrong.  It never
-        should have been committed.  You can use <command>svn
-        merge</command> to <quote>undo</quote> the change in your
-        working copy, and then commit the local modification to the
-        repository.  All you need to do is to specify a
-        <emphasis>reverse</emphasis> difference.  (You can do this by
-        specifying <option>--revision 303:302</option>, or by an
-        equivalent <option>--change -303</option>.)</para>
-
-
-      <screen>
-$ svn merge -c -303 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.
-</screen>
-
-      <para>One way to think about a repository revision is as a
-        specific group of changes (some version control systems call
-        these <firstterm>changesets</firstterm>).  By using the
-        <option>-r</option> option, you can ask <command>svn
-        merge</command> to apply a changeset, or whole range of
-        changesets, to your working copy.  In our case of undoing a
-        change, we're asking <command>svn merge</command> to apply
-        changeset #303 to our working copy
-        <emphasis>backwards</emphasis>.</para>
-
-      <sidebar>
-        <title>Subversion and Changesets</title>
-
-        <para>Everyone seems to have a slightly different definition
-          of <quote>changeset</quote>, or at least a different
-          expectation of what it means for a version control system to
-          have <quote>changeset features</quote>.  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.</para>
-
-        <para>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 <quote>revision N</quote> 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,
-          <quote>this issue was fixed by revision 9238.</quote>.
-          Somebody can then run <command>svn log -r9238</command> to
-          read about the exact changeset which fixed the bug, and run
-          <command>svn diff -c 9238</command> to see the patch
-          itself.  And Subversion's <literal>merge</literal> command
-          also uses revision numbers.  You can merge specific changesets
-          from one branch to another by naming them in the merge
-          arguments: <command>svn merge -r9237:9238</command> would
-          merge changeset #9238 into your working copy.</para>
-      </sidebar>
-
-      <para>Keep in mind that rolling back a change like this is just
-        like any other <command>svn merge</command> operation, so you
-        should use <command>svn status</command> and <command>svn
-        diff</command> to confirm that your work is in the state you
-        want it to be in, and then use <command>svn commit</command>
-        to send the final version to the repository.  After
-        committing, this particular changeset is no longer reflected
-        in the <literal>HEAD</literal> revision.</para>
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <sect2 id="svn.branchmerge.advanced.mergeconflicts">
+      <title>Merge Conflicts</title>
+
+      <para>Just like the <command>svn update</command> command,
+        <command>svn merge</command> applies changes to your working
+        copy.  And therefore it's also capable of creating
+        conflicts.  The conflicts produced by <command>svn
+          merge</command>, however, are sometimes different, and this
+        section explains those differences.</para>
 
-      <para>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
-        <filename>calc</filename> project between revisions 303 and
-        349, they'll still see the bad change, right?</para>
+      <para>To begin with, assume that your working copy has no
+        local edits.  When you <command>svn update</command> to a
+        particular revision, the changes sent by the server will
+        always apply <quote>cleanly</quote> to your working copy.
+        The server produces the delta by comparing two trees: a
+        virtual snapshot of your working copy, and the revision tree
+        you're interested in.  Because the left-hand side of the
+        comparison is exactly equal to what you already have, the
+        delta is guaranteed to correctly convert your working copy
+        into the right-hand tree.</para>
+
+      <para>But <command>svn merge</command> has no such guarantees
+        and can be much more chaotic: the advanced user can ask the
+        server to compare <emphasis>any</emphasis> two trees at all,
+        even ones that are unrelated to the working copy!  This means
+        there's large potential for human error.  Users will sometimes
+        compare the wrong two trees, creating a delta that doesn't
+        apply cleanly.  <command>svn merge</command> will do its best
+        to apply as much of the delta as possible, but some parts may
+        be impossible.  Just as the Unix
+        <command>patch</command> command sometimes complains about
+        <quote>failed hunks</quote>, <command>svn merge</command>
+        will complain about <quote>skipped targets</quote>:</para>
+
+      <screen>
+        $ svn merge -r 1288:1351 http://svn.example.com/repos/branch
+        U  foo.c
+        U  bar.c
+        Skipped missing target: 'baz.c'
+        U  glub.c
+        C  glorb.h
+
+        $
+      </screen>
+
+      <para>In the previous example it might be the case that
+        <filename>baz.c</filename> exists in both snapshots of the
+        branch being compared, and the resulting delta wants to
+        change the file's contents, but the file doesn't exist in
+        the working copy.  Whatever the case, the
+        <quote>skipped</quote> message means that the user is most
+        likely comparing the wrong two trees; they're the classic
+        sign of user error.  When this happens, it's easy to
+        recursively revert all the changes created by the merge
+        (<command>svn revert --recursive</command>), delete any
+        unversioned files or directories left behind after the
+        revert, and re-run <command>svn merge</command> with
+        different arguments.</para>
+
+      <para>Also notice that the previous example shows a conflict
+        happening on <filename>glorb.h</filename>.  We already
+        stated that the working copy has no local edits: how can a
+        conflict possibly happen?  Again, because the user can use
+        <command>svn merge</command> to define and apply any old
+        delta to the working copy, that delta may contain textual
+        changes that don't cleanly apply to a working file, even if
+        the file has no local modifications.</para>
 
-      <para>Yes, that's true.  When we talk about
-        <quote>removing</quote> a change, we're really talking about
-        removing it from <literal>HEAD</literal>.  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 <literal>HEAD</literal> 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.
-        <footnote>
-          <para>The Subversion project has plans, however, to someday
-            implement a command that would accomplish the task of
-            permanently deleting information.  In the meantime, see
-            <xref linkend="svn.reposadmin.maint.tk.svndumpfilter"/>
-            for a possible workaround.</para>
-        </footnote>
-      </para>
+      <para>Another small difference between <command>svn
+          update</command> and <command>svn merge</command> are the
+        names of the full-text files created when a conflict
+        happens.  In <xref linkend="svn.tour.cycle.resolve"/>, we saw
+        that an update produces files named
+        <filename>filename.mine</filename>,
+        <filename>filename.rOLDREV</filename>, and
+        <filename>filename.rNEWREV</filename>.  When <command>svn
+          merge</command> produces a conflict, though, it creates
+        three files named <filename>filename.working</filename>,
+        <filename>filename.left</filename>, and
+        <filename>filename.right</filename>.  In this case, the
+        terms <quote>left</quote> and <quote>right</quote> are
+        describing which side of the double-tree comparison the file
+        came from.  In any case, these differing names will help you
+        distinguish between conflicts that happened as a result of an
+        update versus ones that happened as a result of a
+        merge.</para>
 
     </sect2>
 
-    <!-- =============================================================== -->
-    <sect2 id="svn.branchmerge.commonuses.resurrect">
-      <title>Resurrecting Deleted Items</title>
-
-      <para>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 <literal>HEAD</literal>
-        revision, but the object still exists in earlier revisions.
-        One of the most common questions new users ask is, <quote>How
-        do I get my old file or directory back?</quote>.</para>
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <sect2 id="svn.branchmerge.advanced.blockchanges">
+      <title>Blocking Changes</title>
+
+      <para>###TODO:  discuss use of 'svn merge --record-only', give
+      example.  Explain the need to differentiate between 'not merged'
+      and 'don't want to merge'.  Explain that in 1.5, users need to
+      manualy track blocked revisions in a text file or in property.
+      A future version of svn will learn to differentiate between the
+      two concepts.</para>
 
-      <para>The first step is to define
-        exactly <emphasis role="bold">which</emphasis> 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.  (Remember the
-        <quote>peg revision</quote> syntax—foo.c at 224
-        —mentioned back in
-        <xref linkend="svn.advanced.pegrevs"/>.) </para>
+    </sect2>
 
-      <para>First, you might need to use <command>svn log</command> to
-        discover the exact coordinate pair you wish to resurrect.  A
-        good strategy is to run <command>svn log
-        --verbose</command> in a directory which used to contain your
-        deleted item.  The <option>--verbose (-v)</option> 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 <command>grep</command>, or
-        perhaps via an incremental search in an editor).</para>
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <sect2 id="svn.branchmerge.advanced.logblame">
+      <title>Logging and Blaming</title>
 
-      <screen>
-$ 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.
-…
-</screen>
+      <para>###TODO:  demonstrate 'svn log -g' and 'svn blame -g', and
+        explain why they're useful.</para>
 
-      <para>In the example, we're assuming that you're looking for a
-        deleted file <filename>real.c</filename>.  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
-        <filename>/calc/trunk/real.c</filename> from revision
-        807.</para>
-
-      <para>That was the hard part—the research.  Now that you
-        know what you want to restore, you have two different
-        choices.</para>
+    </sect2>
 
-      <para>One option is to use <command>svn merge</command> to apply
-        revision 808 <quote>in reverse</quote>.  (We've already
-        discussed how to undo changes, see
-        <xref linkend="svn.branchmerge.commonuses.undo"/>.)  This
-        would have the effect of re-adding <filename>real.c</filename>
-        as a local modification.  The file would be scheduled for
-        addition, and after a commit, the file would again exist
-        in <literal>HEAD</literal>.</para>
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <sect2 id="svn.branchmerge.advanced.ancestry">
+      <title>Noticing or Ignoring Ancestry</title>
+
+      <para>When conversing with a Subversion developer, you might
+        very likely hear reference to the term
+        <firstterm>ancestry</firstterm>.  This word is used to
+        describe the relationship between two objects in a
+        repository: if they're related to each other, then one
+        object is said to be an ancestor of the other.</para>
+
+      <para>For example, suppose you commit revision 100, which
+        includes a change to a file <filename>foo.c</filename>.
+        Then <filename>foo.c at 99</filename> is an
+        <quote>ancestor</quote> of <filename>foo.c at 100</filename>.
+        On the other hand, suppose you commit the deletion of
+        <filename>foo.c</filename> in revision 101, and then add a
+        new file by the same name in revision 102.  In this case,
+        <filename>foo.c at 99</filename> and
+        <filename>foo.c at 102</filename> may appear to be related
+        (they have the same path), but in fact are completely
+        different objects in the repository.  They share no history
+        or <quote>ancestry</quote>.</para>
+
+      <para>The reason for bringing this up is to point out an
+        important difference between <command>svn diff</command> and
+        <command>svn merge</command>.  The former command ignores
+        ancestry, while the latter command is quite sensitive to it.
+        For example, if you asked <command>svn diff</command> to
+        compare revisions 99 and 102 of <filename>foo.c</filename>,
+        you would see line-based diffs; the <literal>diff</literal>
+        command is blindly comparing two paths.  But if you asked
+        <command>svn merge</command> to compare the same two objects,
+        it would notice that they're unrelated and first attempt to
+        delete the old file, then add the new file;  the output would
+        indicate a deletion followed by an add:</para>
+
+      <screen>
+        D  foo.c
+        A  foo.c
+      </screen>
 
-      <para>In this particular example, however, this is probably not
-        the best strategy.  Reverse-applying revision 808 would not
-        only schedule <filename>real.c</filename> for addition, but
-        the log message indicates that it would also undo certain
-        changes to <filename>integer.c</filename>, which you don't
-        want.  Certainly, you could reverse-merge revision 808 and
-        then <command>svn revert</command> the local modifications to
-        <filename>integer.c</filename>, but this technique doesn't
-        scale well.  What if there were 90 files changed in revision
-        808?</para>
+      <para>Most merges involve comparing trees that are ancestrally
+        related to one another, and therefore <command>svn
+          merge</command> defaults to this behavior.  Occasionally,
+        however, you may want the <literal>merge</literal> command
+        to compare two unrelated trees.  For example, you may have
+        imported two source-code trees representing different vendor
+        releases of a software project (see <xref
+                                               linkend="svn.advanced.vendorbr"/>).  If you asked
+        <command>svn merge</command> to compare the two trees, you'd
+        see the entire first tree being deleted, followed by an add
+        of the entire second tree!  In these situations, you'll want
+        <command>svn merge</command> to do a path-based comparison
+        only, ignoring any relations between files and directories.
+        Add the <option>--ignore-ancestry</option> option to your
+        merge command, and it will behave just like <command>svn
+          diff</command>.  (And conversely, the
+        <option>--notice-ancestry</option> option will cause
+        <command>svn diff</command> to behave like the
+        <literal>merge</literal> command.)</para>
 
-      <para>A second, more targeted strategy is not to use
-        <command>svn merge</command> at all, but rather the
-        <command>svn copy</command> command.  Simply copy the exact
-        revision and path <quote>coordinate pair</quote> from the
-        repository to your working copy:</para>
+    </sect2>
 
-      <screen>
-$ svn copy -r 807 \
-           http://svn.example.com/repos/calc/trunk/real.c ./real.c
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <sect2 id="svn.branchmerge.advanced.moves">
+      <title>Merges and Moves</title>
+
+      <para>A common desire is to refactor source code, especially
+        in Java-based software projects.  Files and directories are
+        shuffled around and renamed, often causing great disruption
+        to everyone working on the project.  Sounds like a perfect
+        case to use a branch, doesn't it?  Just create a branch,
+        shuffle things around, then merge the branch back to the
+        trunk, right?</para>
+
+      <para>Alas, this scenario doesn't work so well right now, and
+        is considered one of Subversion's current weak spots.  The
+        problem is that Subversion's <command>update</command>
+        command isn't as robust as it should be, particularly when
+        dealing with copy and move operations.</para>
+
+      <para>When you use <command>svn copy</command> to duplicate a
+        file, the repository remembers where the new file came from,
+        but it fails to transmit that information to the client
+        which is running <command>svn update</command>
+        or <command>svn merge</command>.  Instead of telling the
+        client, <quote>Copy that file you already have to this new
+          location</quote>, it instead sends down an entirely new
+        file.  This can lead to problems, especially because the
+        same thing happens with renamed files.  A lesser-known fact
+        about Subversion is that it lacks <quote>true
+          renames</quote>—the <command>svn move</command>
+        command is nothing more than an aggregation of <command>svn
+          copy</command> and <command>svn delete</command>.</para>
 
-$ svn status
-A  +   real.c
+      <para>For example, suppose that while working on your private
+        branch, you rename <filename>integer.c</filename>
+        to <filename>whole.c</filename>.  Effectively you've created
+        a new file in your branch that is a copy of the original
+        file, and deleted the original file.  Meanwhile, back
+        on <filename>trunk</filename>, Sally has committed some
+        improvements to <filename>integer.c</filename>.  Now you
+        decide to merge your branch to the trunk:</para>
+
+      <screen>
+        $ cd calc/trunk
+
+        $ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch
+        D   integer.c
+        A   whole.c
+      </screen>
+
+      <para>This doesn't look so bad at first glance, but it's also
+        probably not what you or Sally expected.  The merge
+        operation has deleted the latest version
+        of <filename>integer.c</filename> file (the one containing
+        Sally's latest changes), and blindly added your
+        new <filename>whole.c</filename> file—which is a
+        duplicate of the <emphasis>older</emphasis> version
+        of <filename>integer.c</filename>.  The net effect is that
+        merging your <quote>rename</quote> to the branch has removed
+        Sally's recent changes from the latest revision!</para>
+
+      <para>This isn't true data-loss; Sally's changes are still in
+        the repository's history, but it may not be immediately
+        obvious that this has happened.  The moral of this story is
+        that until Subversion improves, be very careful about
+        merging copies and renames from one branch to
+        another.</para>
 
-$ svn commit -m "Resurrected real.c from revision 807, /calc/trunk/real.c."
-Adding         real.c
-Transmitting file data .
-Committed revision 1390.
-</screen>
+    </sect2>
 
-      <para>The plus sign in the status output indicates that the item
-        isn't merely scheduled for addition, but scheduled for
-        addition <quote>with history</quote>.  Subversion remembers
-        where it was copied from.  In the future, running <command>svn
-        log</command> 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
-        <filename>real.c</filename> isn't really new; it's a direct
-        descendant of the original, deleted file.</para>
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <sect2 id="svn.branchmerge.advanced.pre1.5clients">
+      <title>Blocking Pre-1.5 Clients</title>
 
-      <para>Although our example shows us resurrecting a file, note
-        that these same techniques work just as well for resurrecting
-        deleted directories.</para>
+      <para>###TODO:  Why you might want to do this.  (How did we
+        decide to do this??)</para>
 
     </sect2>
 
-    <!-- =============================================================== -->
-    <sect2 id="svn.branchmerge.commonuses.patterns">
-      <title>Common Branching Patterns</title>
+  </sect1>
 
-      <para>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.</para>
+  <!-- ================================================================= -->
+  <!-- ================================================================= -->
+  <!-- ================================================================= -->
+  <sect1 id="svn.branchmerge.commonpatterns">
+    <title>Common Branching Patterns</title>
 
-      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-      <sect3 id="svn.branchmerge.commonuses.patterns.release">
-        <title>Release Branches</title>
+    <para>There are many different uses for branching and <command>svn
+        merge</command>, and this section describes the most common ones
+      you're likely to run into.</para>
 
-        <para>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.</para>
+    <para>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.</para>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <sect2 id="svn.branchmerge.commonpatterns.release">
+      <title>Release Branches</title>
+
+      <para>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.</para>
 
-        <para>Here's where version control can help.  The typical
-          procedure looks like this:</para>
+      <para>Here's where version control can help.  The typical
+        procedure looks like this:</para>
 
       <itemizedlist>
 
         <listitem>
           <para><emphasis>Developers commit all new work to the
-                trunk.</emphasis>
+              trunk.</emphasis>
 
-              Day-to-day changes are committed to
-              <filename>/trunk</filename>: new features, bugfixes, and
-              so on.</para>
+            Day-to-day changes are committed to
+            <filename>/trunk</filename>: new features, bugfixes, and
+            so on.</para>
         </listitem>
 
         <listitem>
           <para><emphasis>The trunk is copied to a
-                <quote>release</quote> branch.</emphasis>
+              <quote>release</quote> branch.</emphasis>
 
-              When the team thinks the software is ready for release
-              (say, a 1.0 release), then <filename>/trunk</filename>
-              might be copied to
-              <filename>/branches/1.0</filename>.</para>
+            When the team thinks the software is ready for release
+            (say, a 1.0 release), then <filename>/trunk</filename>
+            might be copied to
+            <filename>/branches/1.0</filename>.</para>
         </listitem>
 
         <listitem>
           <para><emphasis>Teams continue to work in parallel.</emphasis>
 
-              One team begins rigorous testing of the release branch,
-              while another team continues new work (say, for version
-              2.0) on <filename>/trunk</filename>.  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 <quote>frozen</quote> for
-              final testing right before a release.</para>
+            One team begins rigorous testing of the release branch,
+            while another team continues new work (say, for version
+            2.0) on <filename>/trunk</filename>.  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 <quote>frozen</quote> for
+            final testing right before a release.</para>
         </listitem>
 
         <listitem>
           <para><emphasis>The branch is tagged and released.</emphasis>
 
-              When testing is complete,
-              <filename>/branches/1.0</filename> is copied to
-              <filename>/tags/1.0.0</filename> as a reference
-              snapshot.  The tag is packaged and released to
-              customers.</para>
+            When testing is complete,
+            <filename>/branches/1.0</filename> is copied to
+            <filename>/tags/1.0.0</filename> as a reference
+            snapshot.  The tag is packaged and released to
+            customers.</para>
         </listitem>
 
         <listitem>
           <para><emphasis>The branch is maintained over time.</emphasis>
 
-              While work continues on <filename>/trunk</filename> for
-              version 2.0, bugfixes continue to be ported from
-              <filename>/trunk</filename> to
-              <filename>/branches/1.0</filename>.  When enough
-              bugfixes have accumulated, management may decide to do a
-              1.0.1 release: <filename>/branches/1.0</filename> is
-              copied to <filename>/tags/1.0.1</filename>, and the tag
-              is packaged and released.</para>
+            While work continues on <filename>/trunk</filename> for
+            version 2.0, bugfixes continue to be ported from
+            <filename>/trunk</filename> to
+            <filename>/branches/1.0</filename>.  When enough
+            bugfixes have accumulated, management may decide to do a
+            1.0.1 release: <filename>/branches/1.0</filename> is
+            copied to <filename>/tags/1.0.1</filename>, and the tag
+            is packaged and released.</para>
         </listitem>
 
-        </itemizedlist>
-
-        <para>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 <quote>maintenance</quote> mode, and a number
-          of tags representing final shipped versions.</para>
-
-      </sect3>
-
-      <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-      <sect3 id="svn.branchmerge.commonuses.patterns.feature">
-        <title>Feature Branches</title>
-
-        <para>A <firstterm>feature branch</firstterm> 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
-          <filename>/trunk</filename>.  It's a temporary branch
-          created to work on a complex change without interfering with
-          the stability of <filename>/trunk</filename>.  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.</para>
-
-        <para>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
-          <filename>/trunk</filename> 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
-          <emphasis>ever</emphasis> 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.</para>
-
-        <para>Most projects take a middle-of-the-road approach.  They
-          commonly insist that <filename>/trunk</filename> 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
-          <filename>/trunk</filename> were never destabilized), would
-          it be too large a change to review?  If the answer to that
-          question is <quote>yes</quote>, 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.</para>
-
-        <para>Finally, there's the issue of how to best keep a feature
-          branch in <quote>sync</quote> 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.</para>
-
-        <para>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
-          <xref
-          linkend="svn.branchmerge.copychanges.bestprac.track"/>).
-          You'll need to write careful log messages detailing exactly
-          which revision ranges have been merged already (as
-          demonstrated in
-          <xref linkend="svn.branchmerge.commonuses.wholebr"/>).  It
-          may sound intimidating, but it's actually pretty easy to
-          do.</para>
-
-        <para>At some point, you'll be ready to merge the
-          <quote>synchronized</quote> 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:</para>
-
-        <screen>
-$ cd trunk-working-copy
+      </itemizedlist>
 
-$ svn update
-At revision 1910.
+      <para>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 <quote>maintenance</quote> mode, and a number
+        of tags representing final shipped versions.</para>
 
-$ 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
-…
-</screen>
+    </sect2>
 
-        <para>By comparing the <literal>HEAD</literal> revision of the
-          trunk with the <literal>HEAD</literal> 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.</para>
-
-        <para>Another way of thinking about this pattern is that your
-          weekly sync of trunk to branch is analogous to running
-          <command>svn update</command> in a working copy, while the
-          final merge step is analogous to running <command>svn
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <sect2 id="svn.branchmerge.commonpatterns.feature">
+      <title>Feature Branches</title>
+
+      <para>A <firstterm>feature branch</firstterm> 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
+        <filename>/trunk</filename>.  It's a temporary branch
+        created to work on a complex change without interfering with
+        the stability of <filename>/trunk</filename>.  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.</para>
+
+      <para>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
+        <filename>/trunk</filename> 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
+        <emphasis>ever</emphasis> 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.</para>
+
+      <para>Most projects take a middle-of-the-road approach.  They
+        commonly insist that <filename>/trunk</filename> 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
+        <filename>/trunk</filename> were never destabilized), would it
+        be too large a change to review?  If the answer to that
+        question is <quote>yes</quote>, 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.</para>
+
+      <para>Finally, there's the issue of how to best keep a feature
+        branch in <quote>sync</quote> 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.</para>
+
+      <para>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.  You'll need to write
+        careful log messages detailing exactly which revision ranges
+        have been merged already.  It may sound intimidating, but it's
+        actually pretty easy to do.</para>
+
+      <para>At some point, you'll be ready to merge the
+        <quote>synchronized</quote> 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:</para>
+
+      <para>###TODO:  SIMPLIFY THIS EXAMPLE TO SHOW MERGE-TRACKING</para>
+
+      <screen>
+        $ 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
+        …
+      </screen>
+
+      <para>By comparing the <literal>HEAD</literal> revision of the
+        trunk with the <literal>HEAD</literal> 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.</para>
+
+      <para>Another way of thinking about this pattern is that your
+        weekly sync of trunk to branch is analogous to running
+        <command>svn update</command> in a working copy, while the
+        final merge step is analogous to running <command>svn
           commit</command> from a working copy.  After all, what else
-          <emphasis>is</emphasis> a working copy but a very shallow
-          private branch?  It's a branch that's only capable of
-          storing one change at a time.</para>
-
-      </sect3>
+        <emphasis>is</emphasis> a working copy but a very shallow
+        private branch?  It's a branch that's only capable of
+        storing one change at a time.</para>
 
     </sect2>
 




More information about the svnbook-dev mailing list