728 lines
40 KiB
HTML
728 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>
|