[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