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 which 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 外部 diff3項), 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 non-textual 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.
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 body work, 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.
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 HEAD
, 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 HEAD
, 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, 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 now her version of the image is out of date.
Here's where the difficulty sets in. Were Harry and Sally 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 which 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 spit out an image of a busted-up red Mustang with a cracked windshield!
Clearly, 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 コピー・修正・マージの解法項, most of these types of problems go away entirely where perfect communication between Harry and Sally exists. [15] But as one's version control system is, in fact, one form of communication, it follows that having that software facilitate the serialization of non-parallelizable editing efforts is no bad thing. This where Subversion's implementation of the lock-modify-unlock model steps into the spotlight. This is where we talk about Subversion's locking feature, which is similar to the 「reserved checkouts」 mechanisms of other version control systems.
Subversion のロック機能は、主に二つの目的があります。
Serializing access to a versioned object. By allowing a user to programmatically claim the exclusive right to change to a file in the repository, that user can be reasonably confident that energy invested on unmergeable changes won't be wasted—his commit of those changes will succeed.
Aiding communication. By alerting other users that serialization is in effect for a particular versioned object, those other users can reasonably expect that the object is about to be changed by someone else, and they, too, can avoid wasting their time and energy on unmergeable changes that won't be committable due to eventual out-of-dateness.
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 [16] (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.
In the Subversion repository, a lock is a piece of metadata which grants exclusive access to one user to change a file. This user is said to be the lock owner. Each lock also has a unique identifier, typically a long string of characters, known as the lock token. 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 sort of proof that client knows which lock it is using.
To demonstrate lock creation, let's refer back to our example of multiple graphic designers working with 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 svn lock command.
$ svn lock banana.jpg -m "Editing file for tomorrow's release." 'banana.jpg' locked by user 'harry'. $
There are a number of new things demonstrated in the previous example. First, notice that Harry passed the --message (-m)
option to svn lock. Similar to svn commit, the svn lock command can take comments (either via --message (-m)
or --file (-F)
) to describe the reason for locking the file. Unlike svn commit, however, svn lock will not demand a message by launching your preferred text editor. Lock comments are optional, but still recommended to aid communication.
Secondly, 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 svn update and reattempt the locking command. The locking command would also have failed if the file already been locked by someone else.
As you can see, the svn lock command prints confirmation of the successful lock. At this point, the fact that the file is locked becomes apparent in the output of the svn status and svn info reporting subcommands.
$ 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. $
That the svn info command, which does not contact the repository when run against working copy paths, can display the lock token reveals an important fact about lock tokens—that 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 svn status command shows a K
next to the file (short for locKed), indicating that the lock token is present.
これで Harry は banana.jpg
をロックし、Sally は そのファイルを修正したり削除したりできなくなりました:
$ svn delete banana.jpg D banana.jpg $ svn commit -m "Delete useless file." Deleting banana.jpg svn: Commit failed (details follow): svn: DELETE of '/repos/project/!svn/wrk/64bad3a9-96f9-0310-818a-df4224ddc35d/banana.jpg': 423 Locked (http://svn.example.com) $
しかし Harry は banana の色合いをもう少し黄色くしたあと、その変更点を コミットすることができます。理由はロック所有者としての認可を受けている からであり、彼の作業コピーにはそのための正しいロック・トークンがあるためです:
$ svn status M K banana.jpg $ svn commit -m "Make banana more yellow" Sending banana.jpg Transmitting file data . Committed revision 2201. $ svn status $
Notice that after the commit is finished, svn status shows that the lock token is no longer present in working copy. This is the standard behavior of svn commit—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—even on files that weren't committed. 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 images
because he's unsure of which files he needs to change, yet only only changes four of those files, when he runs svn commit images, the process will still release all thirty locks.
This behavior of automatically releasing locks can be overridden with the --no-unlock
option to svn commit. 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 no-unlock
runtime configuration option (see 実行時設定領域項).
もちろんファイルをロックした後、修正を必ずコミットしなくてはならない という義務はありません。ロックは単にsvn unlock コマンドを利用していつでも解除することもできます:
$ svn unlock banana.c 'banana.c' unlocked.
誰かがロックしているせいでコミットに失敗した時には、原因は割と簡単に 調べることができます。一番簡単な方法は svn status --show-updates を実行することです:
$ svn status -u M 23 bar.c M O 32 raisin.jpg * 72 foo.h Status against revision: 105 $
この例では Sally は自分の作業コピーの foo.h
が古いだけでなくコミットしようと思っている二つの修正したファイルの 片方はリポジトリ中でロックされていることもわかります。 O
の記号は 「Other(他の)」 の意味で ロックがファイル上に存在していてそれをしたのは誰か別の人である という意味になります。彼女がコミットしようとしてもraisin.jpg
上のロックが邪魔をするでしょう。Sally はさらにロックしたのは誰で、いつ、 どうしてロックしたのかも知りたいとします。今度は svn info が答えを教えてくれます:
$ 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. $
Just as svn info 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 svn info 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, svn info on a working copy path will show no lock information at all). If the main argument to svn info 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.
それで今回の具体的な例の場合、Sally は Hally が「ちょっとした 修正」のために 2 月 16 日にそのファイルをロックしたことが わかります。今は 6 月であるので、Sally は多分 Hally は自分がロックしたことを 忘れてしまっているのではないかと考えます。彼女は Harry に電話してロック をはずしてくれるように頼むかも知れません。彼がつかまらなければ彼女は 自分で強制的にロックを解除するか、システム管理者にそうしてもらうように頼む かも知れません。
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 breaking the lock.
管理者にとってはロックを解除するのは簡単です。svnlook と svnadmin プログラムはリポジトリに対して直接 ロック状況を表示したり解除することができます。(これらのツールに関しての より詳しい情報は 管理者用ツールキット項を見てください。)
$ 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'. $
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 --force
to the unlock command:
$ 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. $
Now, Sally's initial attempt to unlock failed because she ran svn unlock 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 svn unlock. 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 --force
, the authentication and authorization requirements are ignored, and the remote lock is broken.
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 svn unlock --force and then svn lock 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 steal the lock, which involves breaking and re-locking the file all in one atomic step. To do this, Sally passes the --force
option to svn lock:
$ 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'. $
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 defunct. 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 svn status to contact the repository:
$ svn status K raisin.jpg $ svn status -u B 32 raisin.jpg $ svn update B raisin.jpg $ svn status $
リポジトリロックが解除された場合、 svn status --show-updatesはファイルの隣に B
(Broken の意味)の記号を表示します。 古いトークンに変わって新たしいロックが存在している場合だと T
(sTolen)の記号を表示します。 また svn update は無効になったすべての ロック・トークンを表示し、作業コピーから取り除きます。
svn lockとsvn unlock がどうやってロックを作ったり解放したり強制解除したり横取りしたりするか を見てきました。これは特定のファイルに対する直列化したコミットをしたい という目標を満足するものです。しかし、作業時間を無駄にしないという、 より大きな問題についてはどうなのでしょうか?
たとえば Harry がある画像ファイルをロックしてから編集し始めたとしましょう。 いっぽう、かなり離れた場所にいる Sally も同じことがしたかったとします。 彼女は svn status --show-updatesを実行することを知らないので Harry が 既にそのファイルをロックしていることを知ることができません。彼女は そのファイルを何時間かかけて編集し、その自分の修正点をコミットしようとして はじめてそのファイルはロックされているか、彼女のファイルが最新ではない ことに気づきます。どうであれ、彼女の変更は Harry のものとマージすることが できません。二人のうちのどちらかが自分の作業を捨てなければならず 多くの時間が無駄になります。
Subversion's solution to this problem is to provide a mechanism to remind users that a file ought to be locked before the editing begins. The mechanism is a special property, svn:needs-lock
. 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 svn lock), the file becomes read-write. When the lock is released, the file becomes read-only again.
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 would prevent her from saving changes to the file. This reminds her to lock the file before editing, whereby she discovers the pre-existing lock:
$ /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. $
Users and administrators alike are encouraged to attach the svn:needs-lock
property to any file which cannot be contextually merged. This is the primary technique for encouraging good locking habits and preventing wasted effort.
この属性はロックシステムとは独立して機能するコミュニケーション用の 仕組みであることに注意してください。言いかえるとどのようなファイル も、このプロパティーがあるかどうかにかかわらずロックすることが できます。逆にこの属性の存在だけで、コミット時にリポジトリから常に ロックを要求されるということにはなりません。
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 「hijack」 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. [17]