727 lines
40 KiB
HTML
727 lines
40 KiB
HTML
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
<title>Locking</title>
|
||
<link rel="stylesheet" href="styles.css" type="text/css" />
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2" />
|
||
<style type="text/css">
|
||
body { background-image: url('images/draft.png');
|
||
background-repeat: no-repeat;
|
||
background-position: top left;
|
||
/* The following properties make the watermark "fixed" on the page. */
|
||
/* I think that's just a bit too distracting for the reader... */
|
||
/* background-attachment: fixed; */
|
||
/* background-position: center center; */
|
||
}</style>
|
||
<link rel="home" href="index.html" title="Version Control with Subversion [DRAFT]" />
|
||
<link rel="up" href="svn.advanced.html" title="Chapter 3. Advanced Topics" />
|
||
<link rel="prev" href="svn.advanced.sparsedirs.html" title="Sparse Directories" />
|
||
<link rel="next" href="svn.advanced.externals.html" title="Externals Definitions" />
|
||
</head>
|
||
<body>
|
||
<div class="navheader">
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Locking</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="svn.advanced.sparsedirs.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 3. Advanced Topics</th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="svn.advanced.externals.html">Next</a></td>
|
||
</tr>
|
||
</table>
|
||
<hr />
|
||
</div>
|
||
<div class="sect1" title="Locking">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h2 class="title" style="clear: both"><a id="svn.advanced.locking"></a>Locking</h2>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>Subversion's copy-modify-merge version control model lives
|
||
and dies on its data merging algorithms—specifically on
|
||
how well those algorithms perform when trying to resolve
|
||
conflicts caused by multiple users modifying the same file
|
||
concurrently. Subversion itself provides only one such
|
||
algorithm: a three-way differencing algorithm that is smart
|
||
enough to handle data at a granularity of a single line of text.
|
||
Subversion also allows you to supplement its content merge
|
||
processing with external differencing utilities (as described in
|
||
<a class="xref" href="svn.advanced.externaldifftools.html#svn.advanced.externaldifftools.diff3" title="External diff3">the section called “External diff3”</a> and
|
||
<a class="xref" href="svn.advanced.externaldifftools.html#svn.advanced.externaldifftools.merge" title="External merge">the section called “External merge”</a>), some
|
||
of which may do an even better job, perhaps providing
|
||
granularity of a word or a single character of text. But common
|
||
among those algorithms is that they generally work only on text
|
||
files. The landscape starts to look pretty grim when you start
|
||
talking about content merges of nontextual file formats. And
|
||
when you can't find a tool that can handle that type of merging,
|
||
you begin to run into problems with the copy-modify-merge
|
||
model.</p>
|
||
<p>Let's look at a real-life example of where this model runs
|
||
aground. Harry and Sally are both graphic designers working on
|
||
the same project, a bit of marketing collateral for an
|
||
automobile mechanic. Central to the design of a particular
|
||
poster is an image of a car in need of some bodywork, stored in
|
||
a file using the PNG image format. The poster's layout is
|
||
almost finished, and both Harry and Sally are pleased with the
|
||
particular photo they chose for their damaged car—a baby
|
||
blue 1967 Ford Mustang with an unfortunate bit of crumpling on
|
||
the left front fender.</p>
|
||
<p>Now, as is common in graphic design work, there's a change
|
||
in plans, which causes the car's color to be a concern. So Sally
|
||
updates her working copy to <code class="literal">HEAD</code>, fires up
|
||
her photo-editing software, and sets about tweaking the image so
|
||
that the car is now cherry red. Meanwhile, Harry, feeling
|
||
particularly inspired that day, decides that the image would
|
||
have greater impact if the car also appears to have suffered
|
||
greater impact. He, too, updates to <code class="literal">HEAD</code>,
|
||
and then draws some cracks on the vehicle's windshield. He
|
||
manages to finish his work before Sally finishes hers, and after
|
||
admiring the fruits of his undeniable talent, he commits the
|
||
modified image. Shortly thereafter, Sally is finished with the
|
||
car's new finish and tries to commit her changes. But, as
|
||
expected, Subversion fails the commit, informing Sally that
|
||
her version of the image is now out of date.</p>
|
||
<p>Here's where the difficulty sets in. If Harry and Sally
|
||
were making changes to a text file, Sally would simply update
|
||
her working copy, receiving Harry's changes in the process. In
|
||
the worst possible case, they would have modified the same
|
||
region of the file, and Sally would have to work out by hand the
|
||
proper resolution to the conflict. But these aren't text
|
||
files—they are binary images. And while it's a simple
|
||
matter to describe what one would expect the results of this
|
||
content merge to be, there is precious little chance that any
|
||
software exists that is smart enough to examine the common
|
||
baseline image that each of these graphic artists worked
|
||
against, the changes that Harry made, and the changes that Sally
|
||
made, and then spit out an image of a busted-up red Mustang with
|
||
a cracked windshield!</p>
|
||
<p>Of course, things would have gone more smoothly if Harry and
|
||
Sally had serialized their modifications to the image—if,
|
||
say, Harry had waited to draw his windshield cracks on Sally's
|
||
now-red car, or if Sally had tweaked the color of a car whose
|
||
windshield was already cracked. As is discussed in
|
||
<a class="xref" href="svn.basic.version-control-basics.html#svn.basic.vsn-models.copy-merge" title="The copy-modify-merge solution">the section called “The copy-modify-merge solution”</a>, most of
|
||
these types of problems go away entirely where perfect
|
||
communication between Harry and Sally
|
||
exists.<sup>[<a id="idp34529920" href="#ftn.idp34529920" class="footnote">19</a>]</sup> But as one's version control
|
||
system is, in fact, one form of communication, it follows that
|
||
having that software facilitate the serialization of
|
||
nonparallelizable editing efforts is no bad thing. This is
|
||
where Subversion's implementation of the lock-modify-unlock
|
||
model steps into the spotlight. This is where we talk about
|
||
Subversion's <em class="firstterm">locking</em> feature, which is
|
||
similar to the <span class="quote">“<span class="quote">reserved checkouts</span>”</span> mechanisms of
|
||
other version control systems.</p>
|
||
<p>Subversion's locking feature exists ultimately to minimize
|
||
wasted time and effort. By allowing a user to programmatically
|
||
claim the exclusive right to change a file in the repository,
|
||
that user can be reasonably confident that any energy he invests
|
||
on unmergeable changes won't be wasted—his commit of those
|
||
changes will succeed. Also, because Subversion communicates to
|
||
other users that serialization is in effect for a particular
|
||
versioned object, those users can reasonably expect that the
|
||
object is about to be changed by someone else. They, too, can
|
||
then avoid wasting their time and energy on unmergeable changes
|
||
that won't be committable due to eventual
|
||
out-of-dateness.</p>
|
||
<p>When referring to Subversion's locking feature, one is
|
||
actually talking about a fairly diverse collection of behaviors,
|
||
which include the ability to lock a versioned
|
||
file<sup>[<a id="idp34533792" href="#ftn.idp34533792" class="footnote">20</a>]</sup> (claiming the exclusive right to
|
||
modify the file), to unlock that file (yielding that exclusive
|
||
right to modify), to see reports about which files are locked
|
||
and by whom, to annotate files for which locking before editing
|
||
is strongly advised, and so on. In this section, we'll cover
|
||
all of these facets of the larger locking feature.</p>
|
||
<div class="sidebar" title="The Three Meanings of “Lock”">
|
||
<a id="svn.advanced.locking.meanings"></a>
|
||
<p class="title">
|
||
<b>The Three Meanings of <span class="quote">“<span class="quote">Lock</span>”</span></b>
|
||
</p>
|
||
<p>In this section, and almost everywhere in this book, the
|
||
words <span class="quote">“<span class="quote">lock</span>”</span> and <span class="quote">“<span class="quote">locking</span>”</span> describe
|
||
a mechanism for mutual exclusion between users to avoid
|
||
clashing commits. Unfortunately, there are two other sorts
|
||
of <span class="quote">“<span class="quote">lock</span>”</span> with which Subversion, and therefore
|
||
this book, sometimes needs to be concerned.</p>
|
||
<p>The second is <em class="firstterm">working copy locks</em>,
|
||
used internally by Subversion to prevent clashes between
|
||
multiple Subversion clients operating on the same working
|
||
copy. This is the sort of lock indicated by an
|
||
<code class="computeroutput">L</code> in the third column of
|
||
<span class="command"><strong>svn status</strong></span> output, and removed by the
|
||
<span class="command"><strong>svn cleanup</strong></span> command, as described in <a class="xref" href="svn.tour.cleanup.html" title="Sometimes You Just Need to Clean Up">the section called “Sometimes You Just Need to Clean Up”</a>.</p>
|
||
<p>Third, there are <em class="firstterm">database locks</em>,
|
||
used internally by the Berkeley DB backend to prevent clashes
|
||
between multiple programs trying to access the database. This
|
||
is the sort of lock whose unwanted persistence after an error
|
||
can cause a repository to be <span class="quote">“<span class="quote">wedged,</span>”</span> as
|
||
described in <a class="xref" href="svn.reposadmin.maint.html#svn.reposadmin.maint.recovery" title="Berkeley DB Recovery">the section called “Berkeley DB Recovery”</a>.</p>
|
||
<p>You can generally forget about these other kinds of locks
|
||
until something goes wrong that requires you to care about
|
||
them. In this book, <span class="quote">“<span class="quote">lock</span>”</span> means the first sort
|
||
unless the contrary is either clear from context or explicitly
|
||
stated.</p>
|
||
</div>
|
||
<div class="sect2" title="Creating Locks">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="svn.advanced.locking.creation"></a>Creating Locks</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>In the Subversion repository, a
|
||
<em class="firstterm">lock</em> is a piece of metadata that
|
||
grants exclusive access to one user to change a file. This
|
||
user is said to be the <em class="firstterm">lock owner</em>.
|
||
Each lock also has a unique identifier, typically a long
|
||
string of characters, known as the <em class="firstterm">lock
|
||
token</em>. The repository manages locks, ultimately
|
||
handling their creation, enforcement, and removal. If any
|
||
commit transaction attempts to modify or delete a locked file
|
||
(or delete one of the parent directories of the file), the
|
||
repository will demand two pieces of information—that
|
||
the client performing the commit be authenticated as the lock
|
||
owner, and that the lock token has been provided as part of
|
||
the commit process as a form of proof that the client knows which
|
||
lock it is using.</p>
|
||
<p>To demonstrate lock creation, let's refer back to our
|
||
example of multiple graphic designers working on the same
|
||
binary image files. Harry has decided to change a JPEG image.
|
||
To prevent other people from committing changes to the file
|
||
while he is modifying it (as well as alerting them that he is
|
||
about to change it), he locks the file in the repository using
|
||
the <span class="command"><strong>svn lock</strong></span> command.</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svn lock banana.jpg -m "Editing file for tomorrow's release."
|
||
'banana.jpg' locked by user 'harry'.
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>The preceding example demonstrates a number of new things.
|
||
First, notice that Harry passed the
|
||
<code class="option">--message</code> (<code class="option">-m</code>) option to
|
||
<span class="command"><strong>svn lock</strong></span>. Similar to <span class="command"><strong>svn
|
||
commit</strong></span>, the <span class="command"><strong>svn lock</strong></span> command can
|
||
take comments—via either <code class="option">--message</code>
|
||
(<code class="option">-m</code>) or <code class="option">--file</code>
|
||
(<code class="option">-F</code>)—to describe the reason for locking the
|
||
file. Unlike <span class="command"><strong>svn commit</strong></span>, however,
|
||
<span class="command"><strong>svn lock</strong></span> will not demand a message by
|
||
launching your preferred text editor. Lock comments are
|
||
optional, but still recommended to aid communication.</p>
|
||
<p>Second, the lock attempt succeeded. This means that the
|
||
file wasn't already locked, and that Harry had the latest
|
||
version of the file. If Harry's working copy of the file had
|
||
been out of date, the repository would have rejected the
|
||
request, forcing Harry to <span class="command"><strong>svn update</strong></span> and
|
||
reattempt the locking command. The locking command would also
|
||
have failed if the file had already been locked by someone
|
||
else.</p>
|
||
<p>As you can see, the <span class="command"><strong>svn lock</strong></span> command
|
||
prints confirmation of the successful lock. At this point,
|
||
the fact that the file is locked becomes apparent in the
|
||
output of the <span class="command"><strong>svn status</strong></span> and <span class="command"><strong>svn
|
||
info</strong></span> reporting subcommands.</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svn status
|
||
K banana.jpg
|
||
|
||
$ svn info banana.jpg
|
||
Path: banana.jpg
|
||
Name: banana.jpg
|
||
URL: http://svn.example.com/repos/project/banana.jpg
|
||
Repository UUID: edb2f264-5ef2-0310-a47a-87b0ce17a8ec
|
||
Revision: 2198
|
||
Node Kind: file
|
||
Schedule: normal
|
||
Last Changed Author: frank
|
||
Last Changed Rev: 1950
|
||
Last Changed Date: 2006-03-15 12:43:04 -0600 (Wed, 15 Mar 2006)
|
||
Text Last Updated: 2006-06-08 19:23:07 -0500 (Thu, 08 Jun 2006)
|
||
Properties Last Updated: 2006-06-08 19:23:07 -0500 (Thu, 08 Jun 2006)
|
||
Checksum: 3b110d3b10638f5d1f4fe0f436a5a2a5
|
||
Lock Token: opaquelocktoken:0c0f600b-88f9-0310-9e48-355b44d4a58e
|
||
Lock Owner: harry
|
||
Lock Created: 2006-06-14 17:20:31 -0500 (Wed, 14 Jun 2006)
|
||
Lock Comment (1 line):
|
||
Editing file for tomorrow's release.
|
||
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>The fact that the <span class="command"><strong>svn info</strong></span> command,
|
||
which does not contact the repository when run against working
|
||
copy paths, can display the lock token reveals an important
|
||
piece of information about those tokens: they are cached in
|
||
the working copy. The presence of the lock token is critical.
|
||
It gives the working copy authorization to make use of the
|
||
lock later on. Also, the <span class="command"><strong>svn status</strong></span>
|
||
command shows a <code class="literal">K</code> next to the file (short
|
||
for locKed), indicating that the lock token is present.</p>
|
||
<div class="sidebar" title="Regarding Lock Tokens">
|
||
<p class="title">
|
||
<b>Regarding Lock Tokens</b>
|
||
</p>
|
||
<p>A lock token isn't an authentication token, so much as
|
||
an <span class="emphasis"><em>authorization</em></span> token. The token
|
||
isn't a protected secret. In fact, a lock's unique token is
|
||
discoverable by anyone who runs <strong class="userinput"><code>svn info
|
||
<em class="replaceable"><code>URL</code></em></code></strong>. A lock token is
|
||
special only when it lives inside a working copy. It's
|
||
proof that the lock was created in that particular working
|
||
copy, and not somewhere else by some other client. Merely
|
||
authenticating as the lock owner isn't enough to prevent
|
||
accidents.</p>
|
||
<p>For example, suppose you lock a file using a computer at
|
||
your office, but leave work for the day before you finish
|
||
your changes to that file. It should not be possible to
|
||
accidentally commit changes to that same file from your home
|
||
computer later that evening simply because you've
|
||
authenticated as the lock's owner. In other words, the lock
|
||
token prevents one piece of Subversion-related software from
|
||
undermining the work of another. (In our example, if you
|
||
really need to change the file from an alternative working
|
||
copy, you would need to <em class="firstterm">break</em> the
|
||
lock and relock the file.)</p>
|
||
</div>
|
||
<p>Now that Harry has locked <code class="filename">banana.jpg</code>,
|
||
Sally is unable to change or delete that file:</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svn delete banana.jpg
|
||
D banana.jpg
|
||
$ svn commit -m "Delete useless file."
|
||
Deleting banana.jpg
|
||
svn: Commit failed (details follow):
|
||
svn: Server sent unexpected return value (423 Locked) in response to DELETE\
|
||
request for '/repos/project/!svn/wrk/64bad3a9-96f9-0310-818a-df4224ddc35d/\
|
||
banana.jpg'
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>But Harry, after touching up the banana's shade of yellow,
|
||
is able to commit his changes to the file. That's because he
|
||
authenticates as the lock owner and also because his working
|
||
copy holds the correct lock token:</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svn status
|
||
M K banana.jpg
|
||
$ svn commit -m "Make banana more yellow"
|
||
Sending banana.jpg
|
||
Transmitting file data .
|
||
Committed revision 2201.
|
||
$ svn status
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>Notice that after the commit is finished, <span class="command"><strong>svn
|
||
status</strong></span> shows that the lock token is no longer
|
||
present in the working copy. This is the standard behavior of
|
||
<span class="command"><strong>svn commit</strong></span>—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—<span class="emphasis"><em>even on files that weren't
|
||
committed</em></span>. This is meant to discourage users from
|
||
being sloppy about locking or from holding locks for too long.
|
||
If Harry haphazardly locks 30 files in a directory named
|
||
<code class="filename">images</code> because he's unsure of which files
|
||
he needs to change, yet changes only four of those files, when he
|
||
runs <strong class="userinput"><code>svn commit images</code></strong>, the process will
|
||
still release all 30 locks.</p>
|
||
<p>This behavior of automatically releasing locks can be
|
||
overridden with the <code class="option">--no-unlock</code> option to
|
||
<span class="command"><strong>svn commit</strong></span>. 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
|
||
<code class="literal">no-unlock</code> runtime configuration option (see
|
||
<a class="xref" href="svn.advanced.confarea.html" title="Runtime Configuration Area">the section called “Runtime Configuration Area”</a>).</p>
|
||
<p>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 <span class="command"><strong>svn unlock</strong></span> command:</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svn unlock banana.c
|
||
'banana.c' unlocked.
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
<div class="sect2" title="Discovering Locks">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="svn.advanced.locking.discovery"></a>Discovering Locks</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>When a commit fails due to someone else's locks, it's
|
||
fairly easy to learn about them. The easiest way is to run
|
||
<strong class="userinput"><code>svn status -u</code></strong>:</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svn status -u
|
||
M 23 bar.c
|
||
M O 32 raisin.jpg
|
||
* 72 foo.h
|
||
Status against revision: 105
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>In this example, Sally can see not only that her copy of
|
||
<code class="filename">foo.h</code> is out of date, but also that one of the
|
||
two modified files she plans to commit is locked in the
|
||
repository. The <code class="literal">O</code> symbol stands for
|
||
<span class="quote">“<span class="quote">Other,</span>”</span> meaning that a lock exists on the file
|
||
and was created by somebody else. If she were to attempt a
|
||
commit, the lock on <code class="filename">raisin.jpg</code> would
|
||
prevent it. Sally is left wondering who made the lock, when,
|
||
and why. Once again, <span class="command"><strong>svn info</strong></span> has the
|
||
answers:</p>
|
||
<div class="informalexample">
|
||
<pre class="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.
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>Just as you can use <span class="command"><strong>svn info</strong></span> to examine
|
||
objects in the working copy, you can also use it to examine
|
||
objects in the repository. If the main argument to
|
||
<span class="command"><strong>svn info</strong></span> 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, <span class="command"><strong>svn info</strong></span> on a working copy
|
||
path will show no lock information at all). If the main
|
||
argument to <span class="command"><strong>svn info</strong></span> is a URL, 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.</p>
|
||
<p>So in this particular example, Sally can see that Harry
|
||
locked the file on February 16 to <span class="quote">“<span class="quote">make a quick
|
||
tweak.</span>”</span> 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.</p>
|
||
</div>
|
||
<div class="sect2" title="Breaking and Stealing Locks">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="svn.advanced.locking.break-steal"></a>Breaking and Stealing Locks</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>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. When somebody
|
||
other than the original lock creator destroys a lock, we refer
|
||
to this as <em class="firstterm">breaking the lock</em>.</p>
|
||
<p>From the administrator's chair, it's simple to break
|
||
locks. The <span class="command"><strong>svnlook</strong></span>
|
||
and <span class="command"><strong>svnadmin</strong></span> programs have the ability to
|
||
display and remove locks directly from the repository. (For
|
||
more information about these tools, see
|
||
<a class="xref" href="svn.reposadmin.maint.html#svn.reposadmin.maint.tk" title="An Administrator's Toolkit">the section called “An Administrator's Toolkit”</a>.)</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svnadmin lslocks /var/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 /var/svn/repos /project/raisin.jpg
|
||
Removed lock on '/project/raisin.jpg'.
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>The more interesting option is to allow users to break
|
||
each other's locks over the network. To do this, Sally simply
|
||
needs to pass the <code class="option">--force</code> to the <span class="command"><strong>svn
|
||
unlock</strong></span> command:</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svn status -u
|
||
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.
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>Now, Sally's initial attempt to unlock failed because she
|
||
ran <span class="command"><strong>svn unlock</strong></span> 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 <span class="command"><strong>svn unlock</strong></span>. 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 <code class="option">--force</code>, the authentication and
|
||
authorization requirements are ignored, and the remote lock is
|
||
broken.</p>
|
||
<p>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 relock the file for her own use.
|
||
She can accomplish this by using <span class="command"><strong>svn unlock</strong></span>
|
||
with <code class="option">--force</code> and then <span class="command"><strong>svn lock</strong></span>
|
||
back-to-back, but there's a small chance that somebody else
|
||
might lock the file between the two commands. The simpler thing
|
||
to do is to <em class="firstterm">steal</em> the lock, which involves
|
||
breaking and relocking the file all in one atomic step. To
|
||
do this, Sally passes the <code class="option">--force</code> option
|
||
to <span class="command"><strong>svn lock</strong></span>:</p>
|
||
<div class="informalexample">
|
||
<pre class="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'.
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>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 <em class="firstterm">defunct</em>. 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
|
||
<span class="command"><strong>svn status</strong></span> to contact the
|
||
repository:</p>
|
||
<div class="informalexample">
|
||
<pre class="screen">
|
||
$ svn status
|
||
K raisin.jpg
|
||
$ svn status -u
|
||
B 32 raisin.jpg
|
||
Status against revision: 105
|
||
$ svn update
|
||
Updating '.':
|
||
B raisin.jpg
|
||
Updated to revision 105.
|
||
$ svn status
|
||
$
|
||
</pre>
|
||
</div>
|
||
<p>If the repository lock was broken, then <strong class="userinput"><code>svn
|
||
status --show-updates</code></strong> (<code class="option">-u</code>)
|
||
displays a <code class="literal">B</code> (Broken) symbol next to the
|
||
file. If a new lock exists in place of the old one, then a
|
||
<code class="literal">T</code> (sTolen) symbol is shown. Finally,
|
||
<span class="command"><strong>svn update</strong></span> notices any defunct lock tokens
|
||
and removes them from the working copy.</p>
|
||
<div class="sidebar" title="Locking Policies">
|
||
<p class="title">
|
||
<b>Locking Policies</b>
|
||
</p>
|
||
<p>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, 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 other's locks, it
|
||
represents a cultural failure within the team and the
|
||
problem falls outside the scope of software enforcement.</p>
|
||
<p>Subversion defaults to the <span class="quote">“<span class="quote">softer</span>”</span>
|
||
approach, but still allows administrators to create stricter
|
||
enforcement policies through the use of hook scripts. In
|
||
particular, the <code class="filename">pre-lock</code> and
|
||
<code class="filename">pre-unlock</code> hooks allow administrators
|
||
to decide when lock creation and lock releases are allowed
|
||
to happen. Depending on whether a lock already exists,
|
||
these two hooks can decide whether to allow a certain user
|
||
to break or steal a lock. The
|
||
<code class="filename">post-lock</code> and
|
||
<code class="filename">post-unlock</code> hooks are also available,
|
||
and can be used to send email after locking actions. To
|
||
learn more about repository hooks, see <a class="xref" href="svn.reposadmin.create.html#svn.reposadmin.create.hooks" title="Implementing Repository Hooks">the section called “Implementing Repository Hooks”</a>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2" title="Lock Communication">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="svn.advanced.locking.lock-communication"></a>Lock Communication</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>We've seen how <span class="command"><strong>svn lock</strong></span>
|
||
and <span class="command"><strong>svn unlock</strong></span> 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?</p>
|
||
<p>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 <strong class="userinput"><code>svn status
|
||
-u</code></strong>, 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 his or her work, and a lot of
|
||
time has been wasted.</p>
|
||
<p>Subversion's solution to this problem is to provide a
|
||
mechanism to remind users that a file ought to be locked
|
||
<span class="emphasis"><em>before</em></span> the editing begins. The mechanism
|
||
is a special property: <code class="literal">svn:needs-lock</code>. If
|
||
that property is attached to a file (regardless of its value,
|
||
which is irrelevant), 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 using
|
||
<span class="command"><strong>svn lock</strong></span>), the file becomes read/write.
|
||
When the lock is released, the file becomes read-only
|
||
again.</p>
|
||
<p>The theory, then, is that if the image file has this
|
||
property attached, 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 would
|
||
prevent her from saving changes to the file. This
|
||
reminds her to lock the file before editing, whereby she
|
||
discovers the preexisting lock:</p>
|
||
<div class="informalexample">
|
||
<pre class="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.
|
||
$
|
||
</pre>
|
||
</div>
|
||
<div class="tip" title="Tip" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||
<table border="0" summary="Tip">
|
||
<tr>
|
||
<td rowspan="2" align="center" valign="top" width="25">
|
||
<img alt="[Tip]" src="images/tip.png" />
|
||
</td>
|
||
<th align="left">Tip</th>
|
||
</tr>
|
||
<tr>
|
||
<td align="left" valign="top">
|
||
<p>Users and administrators alike are encouraged to attach
|
||
the <code class="literal">svn:needs-lock</code> property to any file
|
||
that cannot be contextually merged. This is the primary
|
||
technique for encouraging good locking habits and preventing
|
||
wasted effort.</p>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<p>Note that this property is a communication tool that
|
||
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.</p>
|
||
<p>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
|
||
<span class="quote">“<span class="quote">hijack</span>”</span> 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.<sup>[<a id="idp34643696" href="#ftn.idp34643696" class="footnote">21</a>]</sup></p>
|
||
</div>
|
||
<div class="footnotes">
|
||
<br />
|
||
<hr width="100" align="left" />
|
||
<div class="footnote">
|
||
<p><sup>[<a id="ftn.idp34529920" href="#idp34529920" class="para">19</a>] </sup>Communication wouldn't have been such bad
|
||
medicine for Harry and Sally's Hollywood namesakes, either, for
|
||
that matter.</p>
|
||
</div>
|
||
<div class="footnote">
|
||
<p><sup>[<a id="ftn.idp34533792" href="#idp34533792" class="para">20</a>] </sup>Subversion does not currently allow locks on
|
||
directories.</p>
|
||
</div>
|
||
<div class="footnote">
|
||
<p><sup>[<a id="ftn.idp34643696" href="#idp34643696" class="para">21</a>] </sup>Except, perhaps, a classic
|
||
Vulcan mind-meld.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="svn.advanced.sparsedirs.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="svn.advanced.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="svn.advanced.externals.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">Sparse Directories </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Externals Definitions</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div xmlns="" id="svn-footer">
|
||
<hr />
|
||
<p>You are reading <em>Version Control with Subversion</em> (for Subversion 1.7), by Ben Collins-Sussman, Brian W. Fitzpatrick, and C. Michael Pilato.<br />
|
||
This work is licensed under the <a href="http://creativecommons.org/licenses/by/2.0/">Creative Commons Attribution License v2.0</a>.<br />
|
||
To submit comments, corrections, or other contributions to the text, please visit <a href="http://www.svnbook.com/">http://www.svnbook.com/</a>.</p>
|
||
</div>
|
||
</body>
|
||
</html>
|