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

fitz noreply at red-bean.com
Fri Jan 5 02:52:16 CST 2007


Author: fitz
Date: Fri Jan  5 02:52:15 2007
New Revision: 2613

Modified:
   trunk/src/en/book/ch-advanced-topics.xml

Log:
Reviewing: move Peg Revisions section to the end of Advanced Topics so
that we don't scare people away. :-)

* src/en/book/ch-advanced-topics.xml: Movey, movey.


Modified: trunk/src/en/book/ch-advanced-topics.xml
==============================================================================
--- trunk/src/en/book/ch-advanced-topics.xml	(original)
+++ trunk/src/en/book/ch-advanced-topics.xml	Fri Jan  5 02:52:15 2007
@@ -248,314 +248,6 @@
   <!-- ================================================================= -->
   <!-- ================================================================= -->
   <!-- ================================================================= -->
-  <sect1 id="svn.advanced.pegrevs">
-    <title>Peg and Operative Revisions</title>
-
-    <para>We make use of the ability to copy, move, rename, and
-      completely replace files and directories on our computers all
-      the time.  And your version control system shouldn't get in the
-      way of your doing these things with your version-controlled
-      files and directories, either.  Subversion's file management
-      support is quite liberating, affording almost as much
-      flexibility for versioned files as you'd expect when
-      manipulating your unversioned ones.  But that flexibility means
-      that across the lifetime of your repository, a given versioned
-      object might have many paths, and a given path might represent
-      several entirely different versioned objects.  And this
-      introduces a certain level of complexity to your interactions
-      with those paths and objects.</para>
-
-    <para>Subversion is pretty smart about noticing when an object's
-      version history includes such <quote>changes of address</quote>.
-      For example, if you ask for the revision history log of a
-      particular file that was renamed last week, Subversion happily
-      provides all those logs—the revision in which the rename
-      itself happened, plus the logs of relevant revisions both before
-      and after that rename.  So, most of the time, you don't even
-      have to think about such things.  But occasionally, Subversion
-      needs your help to clear up ambiguities.</para>
-
-    <para>The simplest example of this occurs when a directory or file
-      is deleted from version control, and then a new directory or
-      file is created with the same name and added to version control.
-      Clearly the thing you deleted and the thing you later added
-      aren't the same thing.  They merely happen to have had the same
-      path, <filename>/trunk/object</filename> for example.  What,
-      then, does it mean to ask Subversion about the history of
-      <filename>/trunk/object</filename>?  Are you asking about the
-      thing currently at that location, or the old thing you deleted
-      from that location?  Are you asking about the operations that
-      have happened to <emphasis>all</emphasis> the objects that have
-      ever lived at that path?  Clearly, Subversion needs a hint about
-      what you really want.</para>
-
-    <para>And thanks to moves, versioned object history can get far
-      more twisted than that, even.  For example, you might have a
-      directory named <filename>concept</filename>, containing some
-      nascent software project you've been toying with.  Eventually,
-      though, that project matures to the point that the idea seems to
-      actually have some wings, so you do the unthinkable and decide
-      to give the project a name.
-      <footnote>
-        <para><quote>You're not supposed to name it.  Once you name it,
-          you start getting attached to it.</quote> — Mike
-          Wazowski</para>
-      </footnote>
-      Let's say you called your software Frabnaggilywort.  At this
-      point, it makes sense to rename the directory to reflect the
-      project's new name, so <filename>concept</filename> is renamed
-      to <filename>frabnaggilywort</filename>.  Life goes on,
-      Frabnaggilywort releases a 1.0 version, and is downloaded and
-      used daily by hordes of people aiming to improve their
-      lives.</para>
-    
-    <para>It's a nice story, really, but it doesn't end there.
-      Entrepreneur that you are, you've already got another think in
-      the tank.  So you make a new directory,
-      <filename>concept</filename>, and the cycle begins again.  In
-      fact, the cycle begins again many times over the years, each
-      time starting with that old <filename>concept</filename>
-      directory, then sometimes seeing that directory renamed as the
-      idea cures, sometimes seeing it deleted when you scrap the idea.
-      Or, to get really sick, maybe you rename
-      <filename>concept</filename> to something else for a while, but
-      later rename the thing back to <filename>concept</filename> for
-      some reason.</para>
-
-    <para>When scenarios like these occur, attempting to instruct
-      Subversion to work with these re-used paths can be a little like
-      instructing a motorist in Chicago's West Suburbs to drive east
-      down Roosevelt Road and turn left onto Main Street.  In a mere
-      twenty minutes, you can cross <quote>Main Street</quote> in
-      Wheaton, Glen Ellyn, and Lombard.  And no, they aren't the same
-      street.  Our motorist—and our Subversion—need a
-      little more detail in order to do the right thing.</para>
-
-    <para>In version 1.1, Subversion introduced a way for you to tell
-      it exactly which Main Street you meant.  It's called the
-      <firstterm>peg revision</firstterm>, and it is a revision
-      provided to Subversion for the sole purpose of identifying a
-      unique line of history.  Because at most one versioned object
-      may occupy a path at any given time—or, more precisely, in
-      any one revision—the combination of a path and a peg
-      revision is all that is needed to refer to a specific line of
-      history.  Peg revisions are specified to the Subversion
-      command-line client using <firstterm>at syntax</firstterm>, so
-      called because the syntax involves appending an <quote>at
-      sign</quote> (<literal>@</literal>) and the peg revision to the
-      end of the path with which the revision is associated.</para>
-
-    <para>But what of the <option>--revision (-r)</option> of which
-      we've spoken so much in this book?  That revision (or set of
-      revisions) is called the <firstterm>operative
-      revision</firstterm> (or <firstterm>operative revision
-      range</firstterm>).  Once a particular line of history has been
-      identified using a path and peg revision, Subversion performs
-      the requested operation using the operative revision(s).  To map
-      this to our Chicagoland streets analogy, if we are told to go to
-      606 N. Main Street in Wheaton,
-      <footnote>
-        <para>606 N. Main Street, Wheaton, Illinois, is the home of
-          the Wheaton History Center.  Get it—<quote>History
-          Center</quote>?  It seemed appropriate….</para>
-      </footnote>
-      we can think of <quote>Main Street</quote> as our path and
-      <quote>Wheaton</quote> as our peg revision.  These two pieces of
-      information identify a unique path which can travelled (north or
-      south on Main Street), and will keep us from travelling up and
-      down the wrong Main Street in search of our destination.  Now we
-      throw in <quote>606 N.</quote> as our operative revision, of
-      sorts, and we know <emphasis>exactly</emphasis> where to
-      go.</para>
-
-    <sidebar>
-      <title>The peg revision algorithm</title>
-      
-      <para>The Subversion command-line performs the peg revision
-        algorithm any time it needs to resolve possible ambiguities in
-        the paths and revisions provided to it.  Here's an example of
-        such an invocation for the purposes of illustrating that
-        algorithm.</para>
-
-      <screen>
-$ svn <replaceable>command</replaceable> -r <replaceable>OPERATIVE-REV</replaceable> item@<replaceable>PEG-REV</replaceable>
-</screen>
-      
-      <para>The algorithm has three simple steps:</para>
-
-      <itemizedlist>
-        
-        <listitem>
-          <para>Locate <replaceable>item</replaceable> in the revision
-            identified by <replaceable>PEG-REV</replaceable>.  There
-            can be only one such object.</para>
-        </listitem>
-
-        <listitem>
-          <para>Trace the object's history backwards (through any
-            possible renames) to its ancestor in the
-            revision <replaceable>OPERATIVE-REV</replaceable>.</para>
-        </listitem>
-
-        <listitem>
-          <para>Perform the requested action on that ancestor,
-            wherever it is located, or whatever its name might
-            be or have been at that time.</para>
-        </listitem>
-
-      </itemizedlist>
-
-      <para>Note that even when you don't explicitly supply a peg
-        revision or operative revision, they are still present.  For
-        your convenience, the default peg revision is
-        <literal>BASE</literal> for working copy items and
-        <literal>HEAD</literal> for repository URLs.  And when no
-        operative revision is provided, it defaults to being the same
-        revision as the peg revision.</para>
-        
-    </sidebar>
-
-    <para>Say that long ago we created our repository, and in revision 1
-      added our first <filename>concept</filename> directory, plus an
-      <filename>IDEA</filename> file in that directory talking about
-      the concept.  After several revisions in which real code was
-      added and tweaked, we, in revision 20, renamed this directory to
-      <filename>frabnaggilywort</filename>.  By revision 27, we had a
-      new concept, a new <filename>concept</filename> directory to
-      hold it, and a new <filename>IDEA</filename> file to describe
-      it.  And then five years and twenty thousand revisions flew by,
-      just like they would in any good romance story.</para>
-
-    <para>Now, years later, we wonder what the
-      <filename>IDEA</filename> file looked like back in revision 1.
-      But Subversion needs to know if we are asking about how the
-      <emphasis>current</emphasis> file looked back in revision 1, or
-      are we asking for the contents of whatever file lived at
-      <filename>concepts/IDEA</filename> in revision 1?  Certainly
-      those questions have different answers, and because of peg
-      revisions, you can ask either of them.  To find out how the
-      current <filename>IDEA</filename> file looked in that old
-      revision, you run:</para>
-
-    <screen>
-$ svn cat -r 1 concept/IDEA 
-svn: Unable to find repository location for 'concept/IDEA' in revision 1
-</screen>
-
-    <para>Of course, in this example, the current
-      <filename>IDEA</filename> file didn't exist yet in revision 1,
-      so Subversion gives an error.  The command above is shorthand
-      for a longer notation which explicitly lists a peg revision.
-      The expanded notation is:</para>
-
-    <screen>
-$ svn cat -r 1 concept/IDEA at BASE
-svn: Unable to find repository location for 'concept/IDEA' in revision 1
-</screen>
-
-    <para>And when executed, it has the expected results.  Peg revisions
-      generally default to a value of <literal>BASE</literal> (the
-      revision currently present in the working copy) when applied to
-      working copy paths, and of <literal>HEAD</literal> when applied
-      to URLs.</para>
-
-    <para>The perceptive reader is probably wondering at this point if
-      the peg revision syntax causes problems for working copy paths
-      or URLs that actually have at signs in them.  After
-      all, how does <command>svn</command> know whether
-      <literal>news at 11</literal> is the name of a directory in my
-      tree, or just a syntax for <quote>revision 11 of
-      <filename>news</filename></quote>?  Thankfully, while
-      <command>svn</command> will always assume the latter, there is a
-      trivial workaround.  You need only append an at sign to the
-      end of the path, such as <literal>news at 11@</literal>.
-      <command>svn</command> only cares about the last at sign in
-      the argument, and it is not considered illegal to omit a literal
-      peg revision specifier after that at sign.  This workaround
-      even applies to paths that end in an at sign—you would
-      use <literal>filename@@</literal> to talk about a file named
-      <filename>filename@</filename>.</para>
-
-    <para>Let's ask the other question, then—in revision 1, what
-      were the contents of whatever file occupied the address
-      <filename>concepts/IDEA</filename> at the time?  We'll use an
-      explicit peg revision to help us out.</para>
-
-    <screen>
-$ svn cat concept/IDEA at 1
-The idea behind this project is to come up with a piece of software
-that can frab a naggily wort.  Frabbing naggily worts is tricky
-business, and doing it incorrectly can have serious ramifications, so
-we need to employ over-the-top input validation and data verification
-mechanisms.
-</screen>
-
-    <para>Notice that we didn't provide an operative revision this
-      time.  That's because when no operative revision is specified,
-      Subversion assumes a default operative revision that's the same
-      as the peg revision.</para>
-
-    <para>As you can see, the output from our operation appears to be
-      correct.  The text even mentions frabbing naggily worts, so this
-      is almost certainly the file which describes the software now
-      called Frabnaggilywort.  In fact, we can verify this using the
-      combination of an explicit peg revision and explicit operative
-      revision.  We know that in <literal>HEAD</literal>, the
-      Frabnaggilywort project is located in the
-      <filename>frabnaggilywort</filename> directory.  So we specify
-      that we want to see how the line of history identified in
-      <literal>HEAD</literal> as the path
-      <filename>frabnaggilywort/IDEA</filename> looked in revision
-      1.</para>
-
-    <screen>
-$ svn cat -r 1 frabnaggilywort/IDEA at HEAD
-The idea behind this project is to come up with a piece of software
-that can frab a naggily wort.  Frabbing naggily worts is tricky
-business, and doing it incorrectly can have serious ramifications, so
-we need to employ over-the-top input validation and data verification
-mechanisms.
-</screen>
-
-    <para>And the peg and operative revisions need not be so trivial,
-      either.  For example, say <filename>frabnaggilywort</filename>
-      had been deleted from <literal>HEAD</literal>, but we know it
-      existed in revision 20, and we want to see the diffs for its
-      <filename>IDEA</filename> file between revisions 4 and 10.  We
-      can use the peg revision 20 in conjunction with the URL that
-      would have held Frabnaggilywort's <filename>IDEA</filename> file
-      in revision 20, and then use 4 and 10 as our operative revision
-      range.</para>
-
-    <screen>
-$ svn diff -r 4:10 http://svn.red-bean.com/projects/frabnaggilywort/IDEA@20
-Index: frabnaggilywort/IDEA
-===================================================================
---- frabnaggilywort/IDEA	(revision 4)
-+++ frabnaggilywort/IDEA	(revision 10)
-@@ -1,5 +1,5 @@
--The idea behind this project is to come up with a piece of software
--that can frab a naggily wort.  Frabbing naggily worts is tricky
--business, and doing it incorrectly can have serious ramifications, so
--we need to employ over-the-top input validation and data verification
--mechanisms.
-+The idea behind this project is to come up with a piece of
-+client-server software that can remotely frab a naggily wort.
-+Frabbing naggily worts is tricky business, and doing it incorrectly
-+can have serious ramifications, so we need to employ over-the-top
-+input validation and data verification mechanisms.
-</screen>
-
-    <para>Fortunately, most folks aren't faced with such complex
-      situations.  But when you are, remember that peg revisions are
-      that extra hint Subversion needs to clear up ambiguity.</para>
-
-  </sect1>
-
-
-  <!-- ================================================================= -->
-  <!-- ================================================================= -->
-  <!-- ================================================================= -->
   <sect1 id="svn.advanced.props">
     <title>Properties</title>
 
@@ -2252,552 +1944,859 @@
 $
 </screen>
 
-      <para>Notice that after the commit is finished, <command>svn
-        status</command> shows that the lock token is no longer
-        present in working copy.  This is the standard behavior of
-        <command>svn commit</command>—it searches the working
-        copy (or list of targets, if you provide such a list) for
-        local modifications, and sends all the lock tokens it
-        encounters during this walk to the server as part of the
-        commit transaction.  After the commit completes successfully,
-        all of the repository locks that were mentioned are
-        released—<emphasis>even on files that weren't
-        committed</emphasis>.  This is meant to discourage users from
-        being sloppy about locking, or from holding locks for too
-        long.  If Harry haphazardly locks thirty files in a directory
-        named <filename>images</filename> because he's unsure of which
-        files he needs to change, yet only only changes four of those
-        file, when he runs <command>svn commit images</command>, the
-        process will still release all thirty locks.</para>
+      <para>Notice that after the commit is finished, <command>svn
+        status</command> shows that the lock token is no longer
+        present in working copy.  This is the standard behavior of
+        <command>svn commit</command>—it searches the working
+        copy (or list of targets, if you provide such a list) for
+        local modifications, and sends all the lock tokens it
+        encounters during this walk to the server as part of the
+        commit transaction.  After the commit completes successfully,
+        all of the repository locks that were mentioned are
+        released—<emphasis>even on files that weren't
+        committed</emphasis>.  This is meant to discourage users from
+        being sloppy about locking, or from holding locks for too
+        long.  If Harry haphazardly locks thirty files in a directory
+        named <filename>images</filename> because he's unsure of which
+        files he needs to change, yet only only changes four of those
+        file, when he runs <command>svn commit images</command>, the
+        process will still release all thirty locks.</para>
+
+      <para>This behavior of automatically releasing locks can be
+        overridden with the <option>--no-unlock</option> option to
+        <command>svn commit</command>.  This is best used for those
+        times when you want to commit changes, but still plan to make
+        more changes and thus need to retain existing locks.  You can
+        also make this your default behavior by setting the
+        <literal>no-unlock</literal> runtime configuration option (see
+        <xref linkend="svn.advanced.confarea" />).</para>
+
+      <para>Of course, locking a file doesn't oblige one to commit a
+        change to it.  The lock can be released at any time with a
+        simple <command>svn unlock</command> command:</para>
+
+      <screen>
+$ svn unlock banana.c
+'banana.c' unlocked.
+</screen>
+
+    </sect2>
+
+    <!-- =============================================================== -->
+    <sect2 id="svn.advanced.locking.discovery">
+      <title>Discovering locks</title>
+
+      <para>When a commit fails due to someone else's locks, it's
+        fairly easy to learn about them.  The easiest of
+        these is <command>svn status --show-updates</command>:</para>
+
+      <screen>
+$ svn status --show-updates
+M              23   bar.c
+M    O         32   raisin.jpg
+       *       72   foo.h
+Status against revision:     105
+$
+</screen>
+
+      <para>In this example, Sally can see not only that her copy of
+        <filename>foo.h</filename> is out-of-date, but that one of the
+        two modified files she plans to commit is locked in the
+        repository.  The <literal>O</literal> symbol stands for
+        <quote>Other</quote>, meaning that a lock exists on the file,
+        and was created by somebody else.  If she were to attempt a
+        commit, the lock on <filename>raisin.jpg</filename> would
+        prevent it.  Sally is left wondering who made the lock, when,
+        and why.  Once again, <command>svn info</command> has the
+        answers:</para>
+
+      <screen>
+$ svn info http://svn.example.com/repos/project/raisin.jpg
+Path: raisin.jpg
+Name: raisin.jpg
+URL: http://svn.example.com/repos/project/raisin.jpg
+Repository UUID: edb2f264-5ef2-0310-a47a-87b0ce17a8ec
+Revision: 105
+Node Kind: file
+Last Changed Author: sally
+Last Changed Rev: 32
+Last Changed Date: 2006-01-25 12:43:04 -0600 (Sun, 25 Jan 2006)
+Lock Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b
+Lock Owner: harry
+Lock Created: 2006-02-16 13:29:18 -0500 (Thu, 16 Feb 2006)
+Lock Comment (1 line):
+Need to make a quick tweak to this image.
+$
+</screen>
+
+      <para>Just as <command>svn info</command> can be used to examine
+        objects in the working copy, it can also be used to examine
+        objects in the repository.  If the main argument to
+        <command>svn info</command> is a working copy path, then all
+        of the working copy's cached information is displayed; any
+        mention of a lock means that the working copy is holding a
+        lock token (if a file is locked by another user or in another
+        working copy, <command>svn info</command> on a working copy
+        path will show no lock information at all).  If the main
+        argument to <command>svn info</command> is a URL, then the
+        information reflects the latest version of an object in the
+        repository, and any mention of a lock describes the current
+        lock on the object.</para>
+
+      <para>So in this particular example, Sally can see that Harry
+        locked the file on February 16th to <quote>make a quick
+        tweak</quote>.  It being June, she suspects that he probably
+        forgot all about the lock.  She might phone Harry to complain
+        and ask him to release the lock.  If he's unavailable, she
+        might try to forcibly break the lock herself or ask an
+        administrator to do so.</para>
+
+    </sect2>
+
+    <!-- =============================================================== -->
+    <sect2 id="svn.advanced.locking.break-steal">
+      <title>Breaking and stealing locks</title>
+
+      <para>A repository lock isn't sacred—in Subversion's
+        default configuration state, locks can be released not only by
+        the person who created them, but by anyone at all.  When
+        somebody other than the original lock creator destroys a lock,
+        we refer to this as <firstterm>breaking</firstterm> the
+        lock.</para>
+
+      <para>From the administrator's chair, it's simple to break
+        locks.  The <command>svnlook</command>
+        and <command>svnadmin</command> programs have the ability to
+        display and remove locks directly from the repository.  (For
+        more information about these tools, see
+        <xref linkend="svn.reposadmin.maint.tk"/>.)</para>
+
+      <screen>
+$ svnadmin lslocks /usr/local/svn/repos
+Path: /project2/images/banana.jpg
+UUID Token: opaquelocktoken:c32b4d88-e8fb-2310-abb3-153ff1236923
+Owner: frank
+Created: 2006-06-15 13:29:18 -0500 (Thu, 15 Jun 2006)
+Expires: 
+Comment (1 line):
+Still improving the yellow color.
+
+Path: /project/raisin.jpg
+UUID Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b
+Owner: harry
+Created: 2006-02-16 13:29:18 -0500 (Thu, 16 Feb 2006)
+Expires: 
+Comment (1 line):
+Need to make a quick tweak to this image.
+
+$ svnadmin rmlocks /usr/local/svn/repos /project/raisin.jpg
+Removed lock on '/project/raisin.jpg'.
+$
+</screen>
+
+      <para>The more interesting option is allowing users to break
+        each other's locks over the network.  To do this, Sally simply
+        needs to pass the <option>--force</option> to the unlock
+        command:</para>
+
+      <screen>
+$ svn status --show-updates
+M              23   bar.c
+M    O         32   raisin.jpg
+       *       72   foo.h
+Status against revision:     105
+$ svn unlock raisin.jpg
+svn: 'raisin.jpg' is not locked in this working copy
+$ svn info raisin.jpg | grep URL
+URL: http://svn.example.com/repos/project/raisin.jpg
+$ svn unlock http://svn.example.com/repos/project/raisin.jpg
+svn: Unlock request failed: 403 Forbidden (http://svn.example.com)
+$ svn unlock --force http://svn.example.com/repos/project/raisin.jpg
+'raisin.jpg' unlocked.
+$
+</screen>
+
+      <para>Now, Sally's initial attempt to unlock failed because she
+        ran <command>svn unlock</command> directly on her working copy
+        of the file, and no lock token was present.  To remove the
+        lock directly from the repository, she needs to pass a URL
+        to <command>svn unlock</command>.  Her first attempt to unlock
+        the URL fails, because she can't authenticate as the lock
+        owner (nor does she have the lock token).  But when she
+        passes <option>--force</option>, the authentication and
+        authorization requirements are ignored, and the remote lock is
+        broken.</para>
+        
+      <para>Of course, simply breaking a lock may not be enough.  In
+        the running example, Sally may not only want to break Harry's
+        long-forgotten lock, but re-lock the file for her own use.
+        She can accomplish this by running <command>svn unlock
+        --force</command> and then <command>svn lock</command>
+        back-to-back, but there's a small chance that somebody else
+        might lock the file between the two commands.  The simpler thing
+        to is <firstterm>steal</firstterm> the lock, which involves
+        breaking and re-locking the file all in one atomic step.  To
+        do this, Sally passes the <option>--force</option> option
+        to <command>svn lock</command>:</para>
+
+      <screen>
+$ svn lock raisin.jpg
+svn: Lock request failed: 423 Locked (http://svn.example.com)
+$ svn lock --force raisin.jpg
+'raisin.jpg' locked by user 'sally'.
+$
+</screen>
+
+      <para>In any case, whether the lock is broken or stolen, Harry
+        may be in for a surprise.  Harry's working copy still contains
+        the original lock token, but that lock no longer exists.  The
+        lock token is said to be <firstterm>defunct</firstterm>.  The
+        lock represented by the lock-token has either been broken (no
+        longer in the repository), or stolen (replaced with a
+        different lock).  Either way, Harry can see this by asking
+        <command>svn status</command> to contact the
+        repository:</para>
+
+      <screen>
+$ svn status
+     K raisin.jpg
+$ svn status --show-updates
+     B         32   raisin.jpg
+$ svn update
+  B  raisin.jpg
+$ svn status
+$
+</screen>
+
+      <para>If the repository lock was broken, then <command>svn
+        status --show-updates</command> displays a
+        <literal>B</literal> (Broken) symbol next to the file.  If a
+        new lock exists in place of the old one, then a
+        <literal>T</literal> (sTolen) symbol is shown.  Finally,
+        <command>svn update</command> notices any defunct lock tokens
+        and removes them from the working copy.</para>
 
-      <para>This behavior of automatically releasing locks can be
-        overridden with the <option>--no-unlock</option> option to
-        <command>svn commit</command>.  This is best used for those
-        times when you want to commit changes, but still plan to make
-        more changes and thus need to retain existing locks.  You can
-        also make this your default behavior by setting the
-        <literal>no-unlock</literal> runtime configuration option (see
-        <xref linkend="svn.advanced.confarea" />).</para>
+      <sidebar>
+        <title>Locking Policies</title>
+        
+        <para>Different systems have different notions of how strict a
+          lock should be.  Some folks argue that locks must be
+          strictly enforced at all costs, releasable only by the
+          original creator or administrator.  They argue that if
+          anyone can break a lock, then chaos runs rampant and the
+          whole point of locking is defeated.  The other side argues
+          that locks are first and foremost a communication tool.  If
+          users are constantly breaking each others' locks, then it
+          represents a cultural failure within the team and the
+          problem falls outside the scope of software enforcement.</para>
 
-      <para>Of course, locking a file doesn't oblige one to commit a
-        change to it.  The lock can be released at any time with a
-        simple <command>svn unlock</command> command:</para>
+        <para>Subversion defaults to the <quote>softer</quote>
+          approach, but still allows administrators to create stricter
+          enforcement policies through the use of hook scripts.  In
+          particular, the <filename>pre-lock</filename> and
+          <filename>pre-unlock</filename> hooks allow administrators
+          to decide when lock creation and lock releases are allowed
+          to happen.  Depending on whether or not a lock already
+          exists, these two hooks can decide whether or not to allow a
+          certain user to break or steal a lock.  The
+          <filename>post-lock</filename> and
+          <filename>post-unlock</filename> hooks are also available,
+          and can be used to send email after locking actions.  To
+          learn more about repository hooks, see <xref
+          linkend="svn.reposadmin.create.hooks" />.</para>
 
-      <screen>
-$ svn unlock banana.c
-'banana.c' unlocked.
-</screen>
+      </sidebar>
 
     </sect2>
 
     <!-- =============================================================== -->
-    <sect2 id="svn.advanced.locking.discovery">
-      <title>Discovering locks</title>
+    <sect2 id="svn.advanced.locking.lock-communication">
+      <title>Lock Communication</title>
 
-      <para>When a commit fails due to someone else's locks, it's
-        fairly easy to learn about them.  The easiest of
-        these is <command>svn status --show-updates</command>:</para>
+      <para>We've seen how <command>svn lock</command>
+        and <command>svn unlock</command> can be used to create,
+        release, break, and steal locks.  This satisfies the goal of
+        serializing commit access to a file.  But what about the
+        larger problem of preventing wasted time?</para>
 
-      <screen>
-$ svn status --show-updates
-M              23   bar.c
-M    O         32   raisin.jpg
-       *       72   foo.h
-Status against revision:     105
-$
-</screen>
+      <para>For example, suppose Harry locks an image file and then
+        begins editing it.  Meanwhile, miles away, Sally wants to do
+        the same thing.  She doesn't think to run <command>svn status
+        --show-updates</command>, so she has no idea that Harry has
+        already locked the file.  She spends hours editing the file,
+        and when she tries to commit her change, she discovers that
+        either the file is locked or that she's out-of-date.
+        Regardless, her changes aren't mergeable with Harry's.  One of
+        these two people has to throw away their work, and a lot of
+        time has been wasted.</para>
+      
+      <para>Subversion's solution to this problem is to provide a
+        mechanism to remind users that a file ought to be locked
+        <emphasis>before</emphasis> the editing begins.  The mechanism
+        is a special property, <literal>svn:needs-lock</literal>.  If
+        that property is attached to a file (regardless of its value,
+        which is irrelevant), then Subversion will try to use
+        filesystem-level permissions to make the file read-only,
+        unless, of course, the user has explicitly locked the file.
+        When a lock-token is present (as a result of running
+        <command>svn lock</command>), the file becomes read-write.
+        When the lock is released, the file becomes read-only
+        again.</para>
 
-      <para>In this example, Sally can see not only that her copy of
-        <filename>foo.h</filename> is out-of-date, but that one of the
-        two modified files she plans to commit is locked in the
-        repository.  The <literal>O</literal> symbol stands for
-        <quote>Other</quote>, meaning that a lock exists on the file,
-        and was created by somebody else.  If she were to attempt a
-        commit, the lock on <filename>raisin.jpg</filename> would
-        prevent it.  Sally is left wondering who made the lock, when,
-        and why.  Once again, <command>svn info</command> has the
-        answers:</para>
+      <para>The theory, then, is that if the image file has this
+        property attached, then Sally would immediately notice
+        something is strange when she opens the file for editing.
+        Many applications alert users immediately when a read-only
+        file is opened for editing.  And nearly all applications would
+        at least prevert her from saving changes to the file.  This
+        reminds her to lock the file before editing, whereby she
+        discovers the pre-existing lock:</para>
 
       <screen>
-$ svn info http://svn.example.com/repos/project/raisin.jpg
-Path: raisin.jpg
-Name: raisin.jpg
-URL: http://svn.example.com/repos/project/raisin.jpg
-Repository UUID: edb2f264-5ef2-0310-a47a-87b0ce17a8ec
-Revision: 105
-Node Kind: file
-Last Changed Author: sally
-Last Changed Rev: 32
-Last Changed Date: 2006-01-25 12:43:04 -0600 (Sun, 25 Jan 2006)
+$ /usr/local/bin/gimp raisin.jpg
+gimp: error: file is read-only!
+$ ls -l raisin.jpg
+-r--r--r--   1 sally   sally   215589 Jun  8 19:23 raisin.jpg
+$ svn lock raisin.jpg
+svn: Lock request failed: 423 Locked (http://svn.example.com)
+$ svn info http://svn.example.com/repos/project/raisin.jpg | grep Lock
 Lock Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b
 Lock Owner: harry
-Lock Created: 2006-02-16 13:29:18 -0500 (Thu, 16 Feb 2006)
+Lock Created: 2006-06-08 07:29:18 -0500 (Thu, 08 June 2006)
 Lock Comment (1 line):
-Need to make a quick tweak to this image.
+Making some tweaks.  Locking for the next two hours.
 $
 </screen>
 
-      <para>Just as <command>svn info</command> can be used to examine
-        objects in the working copy, it can also be used to examine
-        objects in the repository.  If the main argument to
-        <command>svn info</command> is a working copy path, then all
-        of the working copy's cached information is displayed; any
-        mention of a lock means that the working copy is holding a
-        lock token (if a file is locked by another user or in another
-        working copy, <command>svn info</command> on a working copy
-        path will show no lock information at all).  If the main
-        argument to <command>svn info</command> is a URL, then the
-        information reflects the latest version of an object in the
-        repository, and any mention of a lock describes the current
-        lock on the object.</para>
+      <tip>
+        <para>Users and administrators alike are encouraged to attach
+          the <literal>svn:needs-lock</literal> property to any file
+          which cannot be contextually merged.  This is the primary
+          technique for encouraging good locking habits and preventing
+          wasted effort.</para>
+      </tip>
+
+      <para>Note that this property is a communication tool which
+        works independently from the locking system.  In other words,
+        any file can be locked, whether or not this property is
+        present.  And conversely, the presence of this property
+        doesn't make the repository require a lock when
+        committing.</para>
+
+      <para>Unfortunately, the system isn't flawless.  It's possible
+        that even when a file has the property, the read-only reminder
+        won't always work.  Sometimes applications misbehave and
+        <quote>hijack</quote> the read-only file, silently allowing
+        users to edit and save the file anyway.  There's not much that
+        Subversion can do in this situation—at the end of the
+        day, there's simply no substitution for good interpersonal
+        communication.
+        <footnote>
+          <para>Except, perhaps, a classic Vulcan mind-meld.</para>
+        </footnote>
+      </para>
+
+    </sect2>
+
+  </sect1>
+
+  <!-- ================================================================= -->
+  <!-- ================================================================= -->
+  <!-- ================================================================= -->
+  <sect1 id="svn.advanced.externals">
+    <title>Externals Definitions</title>
+    
+    <para>Sometimes it is useful to construct a working copy that is
+      made out of a number of different checkouts.  For example, you
+      may want different subdirectories to come from different
+      locations in a repository, or perhaps from different
+      repositories altogether.  You could certainly setup such a
+      scenario by hand—using <command>svn checkout</command> to
+      create the sort of nested working copy structure you are trying
+      to achieve.  But if this layout is important for everyone who
+      uses your repository, every other user will need to perform the
+      same checkout operations that you did.</para>
+
+    <para>Fortunately, Subversion provides support for
+      <firstterm>externals definitions</firstterm>.  An externals
+      definition is a mapping of a local directory to the
+      URL—and possibly a particular revision—of a
+      versioned object.  In Subversion, you declare externals
+      definitions in groups using the <literal>svn:externals</literal>
+      property.  You can create or modify this property using
+      <command>svn propset</command> or <command>svn
+      propedit</command> (see <xref linkend="svn.advanced.props.manip"
+      />).  It can be set on any versioned directory, and its value is
+      a multi-line table of subdirectories (relative to the versioned
+      directory on which the property is set) and fully qualified,
+      absolute Subversion repository URLs.</para>
+
+    <screen>
+$ svn propget svn:externals calc
+third-party/sounds             http://sounds.red-bean.com/repos
+third-party/skins              http://skins.red-bean.com/repositories/skinproj
+third-party/skins/toolkit -r21 http://svn.red-bean.com/repos/skin-maker
+</screen>
+
+    <para>The convenience of the <literal>svn:externals</literal>
+      property is that once it is set on a versioned directory,
+      everyone who checks out a working copy with that directory also
+      gets the benefit of the externals definition.  In other words,
+      once one person has made the effort to define those nested
+      working copy checkouts, no one else has to
+      bother—Subversion will, upon checkout of the original
+      working copy, also checkout the external working copies.</para>
+
+    <para>Note the previous externals definition example.  When
+      someone checks out a working copy of the
+      <filename>calc</filename> directory, Subversion also continues
+      to checkout the items found in its externals definition.</para>
+
+    <screen>
+$ svn checkout http://svn.example.com/repos/calc
+A  calc
+A  calc/Makefile
+A  calc/integer.c
+A  calc/button.c
+Checked out revision 148.
+
+Fetching external item into calc/third-party/sounds
+A  calc/third-party/sounds/ding.ogg
+A  calc/third-party/sounds/dong.ogg
+A  calc/third-party/sounds/clang.ogg
+…
+A  calc/third-party/sounds/bang.ogg
+A  calc/third-party/sounds/twang.ogg
+Checked out revision 14.
+
+Fetching external item into calc/third-party/skins
+…
+</screen>
+
+    <para>If you need to change the externals definition, you can do
+      so using the regular property modification subcommands.  When
+      you commit a change to the <literal>svn:externals</literal>
+      property, Subversion will synchronize the checked-out items
+      against the changed externals definition when you next run
+      <command>svn update</command>.  The same thing will happen when
+      others update their working copies and receive your changes to
+      the externals definition.</para>
 
-      <para>So in this particular example, Sally can see that Harry
-        locked the file on February 16th to <quote>make a quick
-        tweak</quote>.  It being June, she suspects that he probably
-        forgot all about the lock.  She might phone Harry to complain
-        and ask him to release the lock.  If he's unavailable, she
-        might try to forcibly break the lock herself or ask an
-        administrator to do so.</para>
+    <tip>
+      <para>Because the <literal>svn:externals</literal> property has
+        a multiline value, we strongly recommend that you use
+        <command>svn propedit</command> instead of <command>svn
+        propset</command>.</para>
+    </tip>
 
-    </sect2>
+    <tip>
+      <para>You should strongly consider using explicit revision
+        numbers in all of your externals definitions.  Doing so means
+        that you get to decide when to pull down a different snapshot
+        of external information, and exactly which snapshot to pull.
+        Besides avoiding the surprise of getting changes to
+        third-party repositories that you might not have any control
+        over, using explicit revision numbers also means that as you
+        backdate your working copy to a previous revision, your
+        externals definitions will also revert to the way they looked
+        in that previous revision, which in turn means that the
+        external working copies will be updated to match they way
+        <emphasis>they</emphasis> looked back when your repository was
+        at that previous revision.  For software projects, this could
+        be the difference between a successful and a failed build of
+        an older snapshot of your complex codebase.</para> 
+    </tip>
 
-    <!-- =============================================================== -->
-    <sect2 id="svn.advanced.locking.break-steal">
-      <title>Breaking and stealing locks</title>
+    <para>The <command>svn status</command> command also recognizes
+      externals definitions, displaying a status code of
+      <literal>X</literal> for the disjoint subdirectories into which
+      externals are checked out, and then recursing into those
+      subdirectories to display the status of the external items
+      themselves.</para>
 
-      <para>A repository lock isn't sacred—in Subversion's
-        default configuration state, locks can be released not only by
-        the person who created them, but by anyone at all.  When
-        somebody other than the original lock creator destroys a lock,
-        we refer to this as <firstterm>breaking</firstterm> the
-        lock.</para>
+    <para>The support that exists for externals definitions in
+      Subversion today can be a little misleading, though.  First, an
+      externals definition can only point to directories, not files.
+      Second, the externals definition cannot point to relative paths
+      (paths like <filename>../../skins/myskin</filename>).  Third, the
+      working copies created via the externals definition support are
+      still disconnected from the primary working copy (on whose
+      versioned directories the <literal>svn:externals</literal>
+      property was actually set).  And Subversion still only truly
+      operates on non-disjoint working copies.  So, for example, if
+      you want to commit changes that you've made in one or more of
+      those external working copies, you must run <command>svn
+      commit</command> explicitly on those working
+      copies—committing on the primary working copy will not
+      recurse into any external ones.</para>
 
-      <para>From the administrator's chair, it's simple to break
-        locks.  The <command>svnlook</command>
-        and <command>svnadmin</command> programs have the ability to
-        display and remove locks directly from the repository.  (For
-        more information about these tools, see
-        <xref linkend="svn.reposadmin.maint.tk"/>.)</para>
+    <para>Also, since the definitions themselves use absolute URLs,
+      moving or copying a directory to which they are attached will
+      not affect what gets checked out as an external (though the
+      relative local target subdirectory will, of course, move with
+      renamed directory).  This can be confusing—even
+      frustrating—in certain situations.  For example, say you
+      have a top-level directory named
+      <filename>my-project</filename>, and you've created an externals
+      definition on one of its subdirectories
+      (<filename>my-project/some-dir</filename>) which tracks the
+      latest revision of another of its subdirectories
+      (<filename>my-project/external-dir</filename>).</para>
 
-      <screen>
-$ svnadmin lslocks /usr/local/svn/repos
-Path: /project2/images/banana.jpg
-UUID Token: opaquelocktoken:c32b4d88-e8fb-2310-abb3-153ff1236923
-Owner: frank
-Created: 2006-06-15 13:29:18 -0500 (Thu, 15 Jun 2006)
-Expires: 
-Comment (1 line):
-Still improving the yellow color.
+    <screen>
+$ svn co http://svn.example.com/projects .
+A    my-project
+A    my-project/some-dir
+A    my-project/external-dir
+…
+Fetching external item into 'my-project/some-dir/subdir'
+Checked out external at revision 11.
 
-Path: /project/raisin.jpg
-UUID Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b
-Owner: harry
-Created: 2006-02-16 13:29:18 -0500 (Thu, 16 Feb 2006)
-Expires: 
-Comment (1 line):
-Need to make a quick tweak to this image.
+Checked out revision 11.
+$ svn pget svn:externals my-project/some-dir
+subdir http://svn.example.com/projects/my-project/external-dir
 
-$ svnadmin rmlocks /usr/local/svn/repos /project/raisin.jpg
-Removed lock on '/project/raisin.jpg'.
 $
 </screen>
 
-      <para>The more interesting option is allowing users to break
-        each other's locks over the network.  To do this, Sally simply
-        needs to pass the <option>--force</option> to the unlock
-        command:</para>
+    <para>Now you use <command>svn move</command> to rename the
+      <filename>my-project</filename> directory.  At this point, your
+      externals definition will still refer to a path under the
+      <filename>my-project</filename> directory, even though that
+      directory no longer exists.</para>
 
-      <screen>
-$ svn status --show-updates
-M              23   bar.c
-M    O         32   raisin.jpg
-       *       72   foo.h
-Status against revision:     105
-$ svn unlock raisin.jpg
-svn: 'raisin.jpg' is not locked in this working copy
-$ svn info raisin.jpg | grep URL
-URL: http://svn.example.com/repos/project/raisin.jpg
-$ svn unlock http://svn.example.com/repos/project/raisin.jpg
-svn: Unlock request failed: 403 Forbidden (http://svn.example.com)
-$ svn unlock --force http://svn.example.com/repos/project/raisin.jpg
-'raisin.jpg' unlocked.
-$
-</screen>
+    <screen>
+$ svn mv -q my-project renamed-project
+$ svn ci -m "Rename my-project to renamed-project."
+Deleting       my-project
+Adding         my-renamed-project
 
-      <para>Now, Sally's initial attempt to unlock failed because she
-        ran <command>svn unlock</command> directly on her working copy
-        of the file, and no lock token was present.  To remove the
-        lock directly from the repository, she needs to pass a URL
-        to <command>svn unlock</command>.  Her first attempt to unlock
-        the URL fails, because she can't authenticate as the lock
-        owner (nor does she have the lock token).  But when she
-        passes <option>--force</option>, the authentication and
-        authorization requirements are ignored, and the remote lock is
-        broken.</para>
-        
-      <para>Of course, simply breaking a lock may not be enough.  In
-        the running example, Sally may not only want to break Harry's
-        long-forgotten lock, but re-lock the file for her own use.
-        She can accomplish this by running <command>svn unlock
-        --force</command> and then <command>svn lock</command>
-        back-to-back, but there's a small chance that somebody else
-        might lock the file between the two commands.  The simpler thing
-        to is <firstterm>steal</firstterm> the lock, which involves
-        breaking and re-locking the file all in one atomic step.  To
-        do this, Sally passes the <option>--force</option> option
-        to <command>svn lock</command>:</para>
+Committed revision 12.
+$ svn up
 
-      <screen>
-$ svn lock raisin.jpg
-svn: Lock request failed: 423 Locked (http://svn.example.com)
-$ svn lock --force raisin.jpg
-'raisin.jpg' locked by user 'sally'.
+Fetching external item into 'renamed-project/some-dir/subdir'
+svn: Target path does not exist
 $
 </screen>
 
-      <para>In any case, whether the lock is broken or stolen, Harry
-        may be in for a surprise.  Harry's working copy still contains
-        the original lock token, but that lock no longer exists.  The
-        lock token is said to be <firstterm>defunct</firstterm>.  The
-        lock represented by the lock-token has either been broken (no
-        longer in the repository), or stolen (replaced with a
-        different lock).  Either way, Harry can see this by asking
-        <command>svn status</command> to contact the
-        repository:</para>
+    <para>Be aware, too, that if you need to re-parent your working
+      copy (using <command>svn switch --relocate</command>), externals
+      definitions will <emphasis>not</emphasis> also be
+      re-parented.</para>
 
-      <screen>
-$ svn status
-     K raisin.jpg
-$ svn status --show-updates
-     B         32   raisin.jpg
-$ svn update
-  B  raisin.jpg
-$ svn status
-$
-</screen>
+    <para>Finally, there might be times when you would prefer that
+      <command>svn</command> subcommands would not recognize or
+      otherwise operate on the external working copies created as the
+      result of externals definition handling.  In those instances,
+      you can pass the <option>--ignore-externals</option> option to
+      the subcommand.</para>
+  </sect1>
 
-      <para>If the repository lock was broken, then <command>svn
-        status --show-updates</command> displays a
-        <literal>B</literal> (Broken) symbol next to the file.  If a
-        new lock exists in place of the old one, then a
-        <literal>T</literal> (sTolen) symbol is shown.  Finally,
-        <command>svn update</command> notices any defunct lock tokens
-        and removes them from the working copy.</para>
+  <!-- ================================================================= -->
+  <!-- ================================================================= -->
+  <!-- ================================================================= -->
+  <sect1 id="svn.advanced.pegrevs">
+    <title>Peg and Operative Revisions</title>
 
-      <sidebar>
-        <title>Locking Policies</title>
-        
-        <para>Different systems have different notions of how strict a
-          lock should be.  Some folks argue that locks must be
-          strictly enforced at all costs, releasable only by the
-          original creator or administrator.  They argue that if
-          anyone can break a lock, then chaos runs rampant and the
-          whole point of locking is defeated.  The other side argues
-          that locks are first and foremost a communication tool.  If
-          users are constantly breaking each others' locks, then it
-          represents a cultural failure within the team and the
-          problem falls outside the scope of software enforcement.</para>
+    <para>We make use of the ability to copy, move, rename, and
+      completely replace files and directories on our computers all
+      the time.  And your version control system shouldn't get in the
+      way of your doing these things with your version-controlled
+      files and directories, either.  Subversion's file management
+      support is quite liberating, affording almost as much
+      flexibility for versioned files as you'd expect when
+      manipulating your unversioned ones.  But that flexibility means
+      that across the lifetime of your repository, a given versioned
+      object might have many paths, and a given path might represent
+      several entirely different versioned objects.  And this
+      introduces a certain level of complexity to your interactions
+      with those paths and objects.</para>
 
-        <para>Subversion defaults to the <quote>softer</quote>
-          approach, but still allows administrators to create stricter
-          enforcement policies through the use of hook scripts.  In
-          particular, the <filename>pre-lock</filename> and
-          <filename>pre-unlock</filename> hooks allow administrators
-          to decide when lock creation and lock releases are allowed
-          to happen.  Depending on whether or not a lock already
-          exists, these two hooks can decide whether or not to allow a
-          certain user to break or steal a lock.  The
-          <filename>post-lock</filename> and
-          <filename>post-unlock</filename> hooks are also available,
-          and can be used to send email after locking actions.  To
-          learn more about repository hooks, see <xref
-          linkend="svn.reposadmin.create.hooks" />.</para>
+    <para>Subversion is pretty smart about noticing when an object's
+      version history includes such <quote>changes of address</quote>.
+      For example, if you ask for the revision history log of a
+      particular file that was renamed last week, Subversion happily
+      provides all those logs—the revision in which the rename
+      itself happened, plus the logs of relevant revisions both before
+      and after that rename.  So, most of the time, you don't even
+      have to think about such things.  But occasionally, Subversion
+      needs your help to clear up ambiguities.</para>
 
-      </sidebar>
+    <para>The simplest example of this occurs when a directory or file
+      is deleted from version control, and then a new directory or
+      file is created with the same name and added to version control.
+      Clearly the thing you deleted and the thing you later added
+      aren't the same thing.  They merely happen to have had the same
+      path, <filename>/trunk/object</filename> for example.  What,
+      then, does it mean to ask Subversion about the history of
+      <filename>/trunk/object</filename>?  Are you asking about the
+      thing currently at that location, or the old thing you deleted
+      from that location?  Are you asking about the operations that
+      have happened to <emphasis>all</emphasis> the objects that have
+      ever lived at that path?  Clearly, Subversion needs a hint about
+      what you really want.</para>
 
-    </sect2>
+    <para>And thanks to moves, versioned object history can get far
+      more twisted than that, even.  For example, you might have a
+      directory named <filename>concept</filename>, containing some
+      nascent software project you've been toying with.  Eventually,
+      though, that project matures to the point that the idea seems to
+      actually have some wings, so you do the unthinkable and decide
+      to give the project a name.
+      <footnote>
+        <para><quote>You're not supposed to name it.  Once you name it,
+          you start getting attached to it.</quote> — Mike
+          Wazowski</para>
+      </footnote>
+      Let's say you called your software Frabnaggilywort.  At this
+      point, it makes sense to rename the directory to reflect the
+      project's new name, so <filename>concept</filename> is renamed
+      to <filename>frabnaggilywort</filename>.  Life goes on,
+      Frabnaggilywort releases a 1.0 version, and is downloaded and
+      used daily by hordes of people aiming to improve their
+      lives.</para>
+    
+    <para>It's a nice story, really, but it doesn't end there.
+      Entrepreneur that you are, you've already got another think in
+      the tank.  So you make a new directory,
+      <filename>concept</filename>, and the cycle begins again.  In
+      fact, the cycle begins again many times over the years, each
+      time starting with that old <filename>concept</filename>
+      directory, then sometimes seeing that directory renamed as the
+      idea cures, sometimes seeing it deleted when you scrap the idea.
+      Or, to get really sick, maybe you rename
+      <filename>concept</filename> to something else for a while, but
+      later rename the thing back to <filename>concept</filename> for
+      some reason.</para>
 
-    <!-- =============================================================== -->
-    <sect2 id="svn.advanced.locking.lock-communication">
-      <title>Lock Communication</title>
+    <para>When scenarios like these occur, attempting to instruct
+      Subversion to work with these re-used paths can be a little like
+      instructing a motorist in Chicago's West Suburbs to drive east
+      down Roosevelt Road and turn left onto Main Street.  In a mere
+      twenty minutes, you can cross <quote>Main Street</quote> in
+      Wheaton, Glen Ellyn, and Lombard.  And no, they aren't the same
+      street.  Our motorist—and our Subversion—need a
+      little more detail in order to do the right thing.</para>
 
-      <para>We've seen how <command>svn lock</command>
-        and <command>svn unlock</command> can be used to create,
-        release, break, and steal locks.  This satisfies the goal of
-        serializing commit access to a file.  But what about the
-        larger problem of preventing wasted time?</para>
+    <para>In version 1.1, Subversion introduced a way for you to tell
+      it exactly which Main Street you meant.  It's called the
+      <firstterm>peg revision</firstterm>, and it is a revision
+      provided to Subversion for the sole purpose of identifying a
+      unique line of history.  Because at most one versioned object
+      may occupy a path at any given time—or, more precisely, in
+      any one revision—the combination of a path and a peg
+      revision is all that is needed to refer to a specific line of
+      history.  Peg revisions are specified to the Subversion
+      command-line client using <firstterm>at syntax</firstterm>, so
+      called because the syntax involves appending an <quote>at
+      sign</quote> (<literal>@</literal>) and the peg revision to the
+      end of the path with which the revision is associated.</para>
 
-      <para>For example, suppose Harry locks an image file and then
-        begins editing it.  Meanwhile, miles away, Sally wants to do
-        the same thing.  She doesn't think to run <command>svn status
-        --show-updates</command>, so she has no idea that Harry has
-        already locked the file.  She spends hours editing the file,
-        and when she tries to commit her change, she discovers that
-        either the file is locked or that she's out-of-date.
-        Regardless, her changes aren't mergeable with Harry's.  One of
-        these two people has to throw away their work, and a lot of
-        time has been wasted.</para>
-      
-      <para>Subversion's solution to this problem is to provide a
-        mechanism to remind users that a file ought to be locked
-        <emphasis>before</emphasis> the editing begins.  The mechanism
-        is a special property, <literal>svn:needs-lock</literal>.  If
-        that property is attached to a file (regardless of its value,
-        which is irrelevant), then Subversion will try to use
-        filesystem-level permissions to make the file read-only,
-        unless, of course, the user has explicitly locked the file.
-        When a lock-token is present (as a result of running
-        <command>svn lock</command>), the file becomes read-write.
-        When the lock is released, the file becomes read-only
-        again.</para>
+    <para>But what of the <option>--revision (-r)</option> of which
+      we've spoken so much in this book?  That revision (or set of
+      revisions) is called the <firstterm>operative
+      revision</firstterm> (or <firstterm>operative revision
+      range</firstterm>).  Once a particular line of history has been
+      identified using a path and peg revision, Subversion performs
+      the requested operation using the operative revision(s).  To map
+      this to our Chicagoland streets analogy, if we are told to go to
+      606 N. Main Street in Wheaton,
+      <footnote>
+        <para>606 N. Main Street, Wheaton, Illinois, is the home of
+          the Wheaton History Center.  Get it—<quote>History
+          Center</quote>?  It seemed appropriate….</para>
+      </footnote>
+      we can think of <quote>Main Street</quote> as our path and
+      <quote>Wheaton</quote> as our peg revision.  These two pieces of
+      information identify a unique path which can travelled (north or
+      south on Main Street), and will keep us from travelling up and
+      down the wrong Main Street in search of our destination.  Now we
+      throw in <quote>606 N.</quote> as our operative revision, of
+      sorts, and we know <emphasis>exactly</emphasis> where to
+      go.</para>
 
-      <para>The theory, then, is that if the image file has this
-        property attached, then Sally would immediately notice
-        something is strange when she opens the file for editing.
-        Many applications alert users immediately when a read-only
-        file is opened for editing.  And nearly all applications would
-        at least prevert her from saving changes to the file.  This
-        reminds her to lock the file before editing, whereby she
-        discovers the pre-existing lock:</para>
+    <sidebar>
+      <title>The peg revision algorithm</title>
+      
+      <para>The Subversion command-line performs the peg revision
+        algorithm any time it needs to resolve possible ambiguities in
+        the paths and revisions provided to it.  Here's an example of
+        such an invocation for the purposes of illustrating that
+        algorithm.</para>
 
       <screen>
-$ /usr/local/bin/gimp raisin.jpg
-gimp: error: file is read-only!
-$ ls -l raisin.jpg
--r--r--r--   1 sally   sally   215589 Jun  8 19:23 raisin.jpg
-$ svn lock raisin.jpg
-svn: Lock request failed: 423 Locked (http://svn.example.com)
-$ svn info http://svn.example.com/repos/project/raisin.jpg | grep Lock
-Lock Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b
-Lock Owner: harry
-Lock Created: 2006-06-08 07:29:18 -0500 (Thu, 08 June 2006)
-Lock Comment (1 line):
-Making some tweaks.  Locking for the next two hours.
-$
+$ svn <replaceable>command</replaceable> -r <replaceable>OPERATIVE-REV</replaceable> item@<replaceable>PEG-REV</replaceable>
 </screen>
+      
+      <para>The algorithm has three simple steps:</para>
 
-      <tip>
-        <para>Users and administrators alike are encouraged to attach
-          the <literal>svn:needs-lock</literal> property to any file
-          which cannot be contextually merged.  This is the primary
-          technique for encouraging good locking habits and preventing
-          wasted effort.</para>
-      </tip>
+      <itemizedlist>
+        
+        <listitem>
+          <para>Locate <replaceable>item</replaceable> in the revision
+            identified by <replaceable>PEG-REV</replaceable>.  There
+            can be only one such object.</para>
+        </listitem>
 
-      <para>Note that this property is a communication tool which
-        works independently from the locking system.  In other words,
-        any file can be locked, whether or not this property is
-        present.  And conversely, the presence of this property
-        doesn't make the repository require a lock when
-        committing.</para>
+        <listitem>
+          <para>Trace the object's history backwards (through any
+            possible renames) to its ancestor in the
+            revision <replaceable>OPERATIVE-REV</replaceable>.</para>
+        </listitem>
 
-      <para>Unfortunately, the system isn't flawless.  It's possible
-        that even when a file has the property, the read-only reminder
-        won't always work.  Sometimes applications misbehave and
-        <quote>hijack</quote> the read-only file, silently allowing
-        users to edit and save the file anyway.  There's not much that
-        Subversion can do in this situation—at the end of the
-        day, there's simply no substitution for good interpersonal
-        communication.
-        <footnote>
-          <para>Except, perhaps, a classic Vulcan mind-meld.</para>
-        </footnote>
-      </para>
+        <listitem>
+          <para>Perform the requested action on that ancestor,
+            wherever it is located, or whatever its name might
+            be or have been at that time.</para>
+        </listitem>
 
-    </sect2>
+      </itemizedlist>
 
-  </sect1>
+      <para>Note that even when you don't explicitly supply a peg
+        revision or operative revision, they are still present.  For
+        your convenience, the default peg revision is
+        <literal>BASE</literal> for working copy items and
+        <literal>HEAD</literal> for repository URLs.  And when no
+        operative revision is provided, it defaults to being the same
+        revision as the peg revision.</para>
+        
+    </sidebar>
 
-  <!-- ================================================================= -->
-  <!-- ================================================================= -->
-  <!-- ================================================================= -->
-  <sect1 id="svn.advanced.externals">
-    <title>Externals Definitions</title>
-    
-    <para>Sometimes it is useful to construct a working copy that is
-      made out of a number of different checkouts.  For example, you
-      may want different subdirectories to come from different
-      locations in a repository, or perhaps from different
-      repositories altogether.  You could certainly setup such a
-      scenario by hand—using <command>svn checkout</command> to
-      create the sort of nested working copy structure you are trying
-      to achieve.  But if this layout is important for everyone who
-      uses your repository, every other user will need to perform the
-      same checkout operations that you did.</para>
+    <para>Say that long ago we created our repository, and in revision 1
+      added our first <filename>concept</filename> directory, plus an
+      <filename>IDEA</filename> file in that directory talking about
+      the concept.  After several revisions in which real code was
+      added and tweaked, we, in revision 20, renamed this directory to
+      <filename>frabnaggilywort</filename>.  By revision 27, we had a
+      new concept, a new <filename>concept</filename> directory to
+      hold it, and a new <filename>IDEA</filename> file to describe
+      it.  And then five years and twenty thousand revisions flew by,
+      just like they would in any good romance story.</para>
 
-    <para>Fortunately, Subversion provides support for
-      <firstterm>externals definitions</firstterm>.  An externals
-      definition is a mapping of a local directory to the
-      URL—and possibly a particular revision—of a
-      versioned object.  In Subversion, you declare externals
-      definitions in groups using the <literal>svn:externals</literal>
-      property.  You can create or modify this property using
-      <command>svn propset</command> or <command>svn
-      propedit</command> (see <xref linkend="svn.advanced.props.manip"
-      />).  It can be set on any versioned directory, and its value is
-      a multi-line table of subdirectories (relative to the versioned
-      directory on which the property is set) and fully qualified,
-      absolute Subversion repository URLs.</para>
+    <para>Now, years later, we wonder what the
+      <filename>IDEA</filename> file looked like back in revision 1.
+      But Subversion needs to know if we are asking about how the
+      <emphasis>current</emphasis> file looked back in revision 1, or
+      are we asking for the contents of whatever file lived at
+      <filename>concepts/IDEA</filename> in revision 1?  Certainly
+      those questions have different answers, and because of peg
+      revisions, you can ask either of them.  To find out how the
+      current <filename>IDEA</filename> file looked in that old
+      revision, you run:</para>
 
     <screen>
-$ svn propget svn:externals calc
-third-party/sounds             http://sounds.red-bean.com/repos
-third-party/skins              http://skins.red-bean.com/repositories/skinproj
-third-party/skins/toolkit -r21 http://svn.red-bean.com/repos/skin-maker
+$ svn cat -r 1 concept/IDEA 
+svn: Unable to find repository location for 'concept/IDEA' in revision 1
 </screen>
 
-    <para>The convenience of the <literal>svn:externals</literal>
-      property is that once it is set on a versioned directory,
-      everyone who checks out a working copy with that directory also
-      gets the benefit of the externals definition.  In other words,
-      once one person has made the effort to define those nested
-      working copy checkouts, no one else has to
-      bother—Subversion will, upon checkout of the original
-      working copy, also checkout the external working copies.</para>
-
-    <para>Note the previous externals definition example.  When
-      someone checks out a working copy of the
-      <filename>calc</filename> directory, Subversion also continues
-      to checkout the items found in its externals definition.</para>
+    <para>Of course, in this example, the current
+      <filename>IDEA</filename> file didn't exist yet in revision 1,
+      so Subversion gives an error.  The command above is shorthand
+      for a longer notation which explicitly lists a peg revision.
+      The expanded notation is:</para>
 
     <screen>
-$ svn checkout http://svn.example.com/repos/calc
-A  calc
-A  calc/Makefile
-A  calc/integer.c
-A  calc/button.c
-Checked out revision 148.
-
-Fetching external item into calc/third-party/sounds
-A  calc/third-party/sounds/ding.ogg
-A  calc/third-party/sounds/dong.ogg
-A  calc/third-party/sounds/clang.ogg
-…
-A  calc/third-party/sounds/bang.ogg
-A  calc/third-party/sounds/twang.ogg
-Checked out revision 14.
-
-Fetching external item into calc/third-party/skins
-…
+$ svn cat -r 1 concept/IDEA at BASE
+svn: Unable to find repository location for 'concept/IDEA' in revision 1
 </screen>
 
-    <para>If you need to change the externals definition, you can do
-      so using the regular property modification subcommands.  When
-      you commit a change to the <literal>svn:externals</literal>
-      property, Subversion will synchronize the checked-out items
-      against the changed externals definition when you next run
-      <command>svn update</command>.  The same thing will happen when
-      others update their working copies and receive your changes to
-      the externals definition.</para>
+    <para>And when executed, it has the expected results.  Peg revisions
+      generally default to a value of <literal>BASE</literal> (the
+      revision currently present in the working copy) when applied to
+      working copy paths, and of <literal>HEAD</literal> when applied
+      to URLs.</para>
 
-    <tip>
-      <para>Because the <literal>svn:externals</literal> property has
-        a multiline value, we strongly recommend that you use
-        <command>svn propedit</command> instead of <command>svn
-        propset</command>.</para>
-    </tip>
+    <para>The perceptive reader is probably wondering at this point if
+      the peg revision syntax causes problems for working copy paths
+      or URLs that actually have at signs in them.  After
+      all, how does <command>svn</command> know whether
+      <literal>news at 11</literal> is the name of a directory in my
+      tree, or just a syntax for <quote>revision 11 of
+      <filename>news</filename></quote>?  Thankfully, while
+      <command>svn</command> will always assume the latter, there is a
+      trivial workaround.  You need only append an at sign to the
+      end of the path, such as <literal>news at 11@</literal>.
+      <command>svn</command> only cares about the last at sign in
+      the argument, and it is not considered illegal to omit a literal
+      peg revision specifier after that at sign.  This workaround
+      even applies to paths that end in an at sign—you would
+      use <literal>filename@@</literal> to talk about a file named
+      <filename>filename@</filename>.</para>
 
-    <tip>
-      <para>You should strongly consider using explicit revision
-        numbers in all of your externals definitions.  Doing so means
-        that you get to decide when to pull down a different snapshot
-        of external information, and exactly which snapshot to pull.
-        Besides avoiding the surprise of getting changes to
-        third-party repositories that you might not have any control
-        over, using explicit revision numbers also means that as you
-        backdate your working copy to a previous revision, your
-        externals definitions will also revert to the way they looked
-        in that previous revision, which in turn means that the
-        external working copies will be updated to match they way
-        <emphasis>they</emphasis> looked back when your repository was
-        at that previous revision.  For software projects, this could
-        be the difference between a successful and a failed build of
-        an older snapshot of your complex codebase.</para> 
-    </tip>
+    <para>Let's ask the other question, then—in revision 1, what
+      were the contents of whatever file occupied the address
+      <filename>concepts/IDEA</filename> at the time?  We'll use an
+      explicit peg revision to help us out.</para>
 
-    <para>The <command>svn status</command> command also recognizes
-      externals definitions, displaying a status code of
-      <literal>X</literal> for the disjoint subdirectories into which
-      externals are checked out, and then recursing into those
-      subdirectories to display the status of the external items
-      themselves.</para>
+    <screen>
+$ svn cat concept/IDEA at 1
+The idea behind this project is to come up with a piece of software
+that can frab a naggily wort.  Frabbing naggily worts is tricky
+business, and doing it incorrectly can have serious ramifications, so
+we need to employ over-the-top input validation and data verification
+mechanisms.
+</screen>
 
-    <para>The support that exists for externals definitions in
-      Subversion today can be a little misleading, though.  First, an
-      externals definition can only point to directories, not files.
-      Second, the externals definition cannot point to relative paths
-      (paths like <filename>../../skins/myskin</filename>).  Third, the
-      working copies created via the externals definition support are
-      still disconnected from the primary working copy (on whose
-      versioned directories the <literal>svn:externals</literal>
-      property was actually set).  And Subversion still only truly
-      operates on non-disjoint working copies.  So, for example, if
-      you want to commit changes that you've made in one or more of
-      those external working copies, you must run <command>svn
-      commit</command> explicitly on those working
-      copies—committing on the primary working copy will not
-      recurse into any external ones.</para>
+    <para>Notice that we didn't provide an operative revision this
+      time.  That's because when no operative revision is specified,
+      Subversion assumes a default operative revision that's the same
+      as the peg revision.</para>
 
-    <para>Also, since the definitions themselves use absolute URLs,
-      moving or copying a directory to which they are attached will
-      not affect what gets checked out as an external (though the
-      relative local target subdirectory will, of course, move with
-      renamed directory).  This can be confusing—even
-      frustrating—in certain situations.  For example, say you
-      have a top-level directory named
-      <filename>my-project</filename>, and you've created an externals
-      definition on one of its subdirectories
-      (<filename>my-project/some-dir</filename>) which tracks the
-      latest revision of another of its subdirectories
-      (<filename>my-project/external-dir</filename>).</para>
+    <para>As you can see, the output from our operation appears to be
+      correct.  The text even mentions frabbing naggily worts, so this
+      is almost certainly the file which describes the software now
+      called Frabnaggilywort.  In fact, we can verify this using the
+      combination of an explicit peg revision and explicit operative
+      revision.  We know that in <literal>HEAD</literal>, the
+      Frabnaggilywort project is located in the
+      <filename>frabnaggilywort</filename> directory.  So we specify
+      that we want to see how the line of history identified in
+      <literal>HEAD</literal> as the path
+      <filename>frabnaggilywort/IDEA</filename> looked in revision
+      1.</para>
 
     <screen>
-$ svn co http://svn.example.com/projects .
-A    my-project
-A    my-project/some-dir
-A    my-project/external-dir
-…
-Fetching external item into 'my-project/some-dir/subdir'
-Checked out external at revision 11.
-
-Checked out revision 11.
-$ svn pget svn:externals my-project/some-dir
-subdir http://svn.example.com/projects/my-project/external-dir
-
-$
+$ svn cat -r 1 frabnaggilywort/IDEA at HEAD
+The idea behind this project is to come up with a piece of software
+that can frab a naggily wort.  Frabbing naggily worts is tricky
+business, and doing it incorrectly can have serious ramifications, so
+we need to employ over-the-top input validation and data verification
+mechanisms.
 </screen>
 
-    <para>Now you use <command>svn move</command> to rename the
-      <filename>my-project</filename> directory.  At this point, your
-      externals definition will still refer to a path under the
-      <filename>my-project</filename> directory, even though that
-      directory no longer exists.</para>
+    <para>And the peg and operative revisions need not be so trivial,
+      either.  For example, say <filename>frabnaggilywort</filename>
+      had been deleted from <literal>HEAD</literal>, but we know it
+      existed in revision 20, and we want to see the diffs for its
+      <filename>IDEA</filename> file between revisions 4 and 10.  We
+      can use the peg revision 20 in conjunction with the URL that
+      would have held Frabnaggilywort's <filename>IDEA</filename> file
+      in revision 20, and then use 4 and 10 as our operative revision
+      range.</para>
 
     <screen>
-$ svn mv -q my-project renamed-project
-$ svn ci -m "Rename my-project to renamed-project."
-Deleting       my-project
-Adding         my-renamed-project
-
-Committed revision 12.
-$ svn up
-
-Fetching external item into 'renamed-project/some-dir/subdir'
-svn: Target path does not exist
-$
+$ svn diff -r 4:10 http://svn.red-bean.com/projects/frabnaggilywort/IDEA@20
+Index: frabnaggilywort/IDEA
+===================================================================
+--- frabnaggilywort/IDEA	(revision 4)
++++ frabnaggilywort/IDEA	(revision 10)
+@@ -1,5 +1,5 @@
+-The idea behind this project is to come up with a piece of software
+-that can frab a naggily wort.  Frabbing naggily worts is tricky
+-business, and doing it incorrectly can have serious ramifications, so
+-we need to employ over-the-top input validation and data verification
+-mechanisms.
++The idea behind this project is to come up with a piece of
++client-server software that can remotely frab a naggily wort.
++Frabbing naggily worts is tricky business, and doing it incorrectly
++can have serious ramifications, so we need to employ over-the-top
++input validation and data verification mechanisms.
 </screen>
 
-    <para>Be aware, too, that if you need to re-parent your working
-      copy (using <command>svn switch --relocate</command>), externals
-      definitions will <emphasis>not</emphasis> also be
-      re-parented.</para>
+    <para>Fortunately, most folks aren't faced with such complex
+      situations.  But when you are, remember that peg revisions are
+      that extra hint Subversion needs to clear up ambiguity.</para>
 
-    <para>Finally, there might be times when you would prefer that
-      <command>svn</command> subcommands would not recognize or
-      otherwise operate on the external working copies created as the
-      result of externals definition handling.  In those instances,
-      you can pass the <option>--ignore-externals</option> option to
-      the subcommand.</para>
   </sect1>
 
 </chapter>




More information about the svnbook-dev mailing list