Subversion の 「コピー・修正・マージ」 モデルは プログラムソースコードのように行を基本としたテキストファイルからなる プロジェクト上で共同作業する場合には最適です。しかし ロックが必要な場合で議論した ように、時には Subversion の標準的な共同作業モデルのかわりに 「ロック・修正・ロック解除」モデルを使わなくてはならないことも あります。ファイルがバイナリデータから構成されている場合、異なるユーザに よる二つの修正をマージするのは困難であったり不可能なことがよくあります。 このため Subversion 1.2 とそれ以降ではロック、 あるいは他のバージョン管理システムでは「保護されたチェックアウト (reserved checkouts)」として知られている機能を提供しています。
Subversion のロック機能は主に二つの目標があります:
リソースに対する直列化されたアクセス。 ユーザがリポジトリ中のファイルを変更するための排他的な権限を取得できる ようにします。Harry がfoo.jpgを変更する権利を 取得した場合、Sally にはそのファイルの変更点をコミットするのを禁止すべき です。
開発者間のコミュニケーション支援. ユーザがマージ不能な変更をしてしまうような時間のロスを防ぎます。Harry が foo.jpgの変更権限を取得した場合、Sally はすぐにそれに 気づいて同じファイルに対する作業を避けることができるようにすべきです。
Subversion のロック機能は現時点ではファイルだけに制限されています— ディレクトリツリー全体へのアクセスに対する利用はまだできません。
Subversion リポジトリではロックとは あるユーザがファイルを修正する排他的な権限を与える小さなメタデータ です。このユーザはロックの所有者と呼ばれます。 ロックごとにユニークな識別子があり、普通これは長い文字列の形を したもので、 ロック・トークンと言われます。 リポジトリは独立したテーブル中にロック情報を管理し、コミット操作の最中に 強制的にロックをかけます。コミットのトランザクションがファイルを修正 または削除しようとした場合(あるいはファイルの親を削除しようとした場合)、 リポジトリは二つの情報を要求します:
ユーザ認証。 コミットを実行しようとするクライアントはロック所有者として認証されなくては なりません。
ソフトウェアによる認可 。ユーザの作業コピーはコミットと共にロック・トークン を送信しなくてはならず、これによってどのロックを利用中であるかを正しく知る ことができます。
以下の例によって順序よく説明していきます。Harry が JPEG 画像を修正することに 決めたとしましょう。他の人たちがそのファイルに対する修正をコミットしないように 彼はリポジトリ中のファイルをsvn lockコマンドによって ロックします:
$ svn lock banana.jpg --message "Editing file for tomorrow's release." 'banana.jpg' locked by user 'harry'. $ 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: 2005-03-15 12:43:04 -0600 (Tue, 15 Mar 2005) Text Last Updated: 2005-06-08 19:23:07 -0500 (Wed, 08 Jun 2005) Properties Last Updated: 2005-06-08 19:23:07 -0500 (Wed, 08 Jun 2005) Checksum: 3b110d3b10638f5d1f4fe0f436a5a2a5 Lock Token: opaquelocktoken:0c0f600b-88f9-0310-9e48-355b44d4a58e Lock Owner: harry Lock Created: 2005-06-14 17:20:31 -0500 (Tue, 14 Jun 2005) Lock Comment (1 line): Editing file for tomorrow's release.
前の例には新しい話がたくさん含まれています。まず Harry は svn lock に --message オプションを 渡しています。svn commitと同様、svn lockコマンドは( --message (-m)または --file (-F)オプションによって)コメントをつけてそのファイル をロックした理由を説明することができます。svn commitと違うのはsvn lockは 自分の好きなエディタによる メッセージを常に要求するわけではないところです。ロックのコメントは オプションですが、コミュニケーションを円滑にするためにつけることを お勧めします。
つぎにロックが成功しています。これはそのファイルはまだロックされて いなかったこと、そして Harry がそのファイルの最新バージョンを得たことを 意味しています。もし Harry の作業コピー中のファイルが古いものであれば リポジトリはその要求を拒否し、Harry に対してまずsvn update を実行してから再びロックコマンドを発行するように要求します。
リポジトリ中にロックを作成した後、作業コピーはロックについての情報 をキャッシュすることにも注意してください—そのうち最も重要なのは ロック・トークンです。ロック・トークンの存在は非常に重要です。作業コピー はそれによって後でロック機能の認可を受けるからです。 svn statusコマンドはファイル名のとなりに (locKed の省略として)Kを表示しロック・トークンが存在 していることを示します。
これで Harry は banana.jpg をロックし、Sally は そのファイルを修正したり削除したりできなくなりました:
$ whoami 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 の色合いをもう少し黄色くしたあと、その変更点を コミットすることができます。理由はロック所有者としての認可を受けている からであり、彼の作業コピーにはそのための正しいロック・トークンがあるためです:
$ whoami harry $ svn status M K banana.jpg $ svn commit -m "Make banana more yellow" Sending banana.jpg Transmitting file data . Committed revision 2201. $ svn status $
コミット実行後 svn status がロック・トークンが もう作業コピーに存在していないことを示しているのに注意してください。 これが svn commitの普通の動作です: 作業コピーを (あるいは一覧表を用意していた場合はそのリストを)調べてコミット トランザクションの一環として検出したすべてのロック・トークンをサーバに 送信します。コミットが成功した後で今回関係していたリポジトリ中のすべて のロックは解除されます—そしてこれはコミット対象とは ならなかったファイルにたいしてもそうなります。 この理由はユーザがみだりにロックしないようにすること、そしてあまり長く ロックし続けないようにするためです。たとえば Harry はおおざっぱに imagesという名前のディレクトリ中にある 30 個のファイル にロックしたとします。どのファイルを変更したいのかはっきりしていなかった からです。最終的に、彼は 4 個のファイルに対してだけ修正を加えました。 svn commit imagesを実行するときそのプロセスは残りファイルも 含めた 30 個すべてのロックを解除するでしょう。
この動作は svn commitに--no-unlockオプション を指定することで上書きできます。これは修正をコミットしたいが、 さらに別の変更する計画があり、ロックを残しておく必要があるような場合に 一番よく使われます。この動作は実行時 configファイル にno-unlock = yesを設定することによって半永久的に 調整することもできます(実行時設定領域の項 を見てください。)
もちろんファイルをロックした後、修正を必ずコミットしなくてはならない という義務はありません。ロックは単にsvn unlock コマンドを利用していつでも解除することもできます:
$ svn unlock banana.c 'banana.c' unlocked.
誰かがロックしているせいでコミットに失敗した時には、原因は割と簡単に 調べることができます。一番簡単な方法は svn status --show-updates を実行することです:
$ whoami sally $ svn status --show-updates 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: 2005-01-25 12:43:04 -0600 (Tue, 25 Jan 2005) Lock Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b Lock Owner: harry Lock Created: 2005-02-16 13:29:18 -0500 (Wed, 16 Feb 2005) Lock Comment (1 line): Need to make a quick tweak to this image.
svn infoは作業コピー中のオブジェクトの調査にも利用 できますが、リポジトリ中のオブジェクトに対しても調査することができます。 svn infoの引数で作業コピーのパスを指定した 場合には作業コピーにキャッシュされているすべての情報が表示されます; ロックに関する上記メッセージのすべては作業コピーがロック・トークンを 持っていることを示しています。(ファイルが別のユーザか別の作業コピーに よってロックされている場合、作業コピーパスでのsvn info はロックに関する情報をまったく表示しません)。 svn infoの引数が URL なら情報はリポジトリ中のオブジェクトの 最新バージョンに関するものになります; ロックについての表示はそのオブジェクト の現在のロック状況を示しています。
それで今回の具体的な例の場合、Sally は Hally が「ちょっとした 修正」のために 2 月 16 日にそのファイルをロックしたことが わかります。今は 6 月であるので、Sally は多分 Hally は自分がロックしたことを 忘れてしまっているのではないかと考えます。彼女は Harry に電話してロック をはずしてくれるように頼むかも知れません。彼がつかまらなければ彼女は 自分で強制的にロックを解除するか、システム管理者にそうしてもらうように頼む かも知れません。
リポジトリのロックは不可侵のものではありません; それはロックした人によっても あるいはまったく別の人によっても解除することができます。ロック作成者以外 の別の人がロックを取り除いた場合、ロックは解除された と言います。
管理者にとってはロックを解除するのは簡単です。svnlook と svnadmin プログラムはリポジトリに対して直接 ロック状況を表示したり解除することができます。(これらのツールに関しての より詳しい情報は 管理者用ツールキットの項を見てください。)
$ svnadmin lslocks /usr/local/svn/repos Path: /project2/images/banana.jpg UUID Token: opaquelocktoken:c32b4d88-e8fb-2310-abb3-153ff1236923 Owner: frank Created: 2005-06-15 13:29:18 -0500 (Wed, 15 Jun 2005) Expires: Comment (1 line): Still improving the yellow color. Path: /project/raisin.jpg UUID Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b Owner: harry Created: 2005-02-16 13:29:18 -0500 (Wed, 16 Feb 2005) 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'.
さらに興味深いオプションがあって、ネットワーク越しに人のロックを 解除することができます。これには unlock コマンドに対して --forceを渡すだけです:
$ whoami sally $ svn status --show-updates M 23 bar.c M O 32 raisin.jpg * 72 foo.h Status against revision: 105 $ svn unlock raisin.jpg svn: 'raisin.jpg' is not locked in this working copy $ svn info raisin.jpg | grep URL URL: http://svn.example.com/repos/project/raisin.jpg $ svn unlock http://svn.example.com/repos/project/raisin.jpg svn: Unlock request failed: 403 Forbidden (http://svn.example.com) $ svn unlock --force http://svn.example.com/repos/project/raisin.jpg 'raisin.jpg' unlocked.
サリーが最初に unlock に失敗したのは自分の作業コピー中のファイルに対して 直接 svn unlockを実行したのに、そこにはロックが存在 していなかったためです。リポジトリから直接ロックを取り除くには svn unlock に URL の引数を渡す必要があります。 URL をロック解除しようという最初の試みには失敗していますが、それは ロック所有者の認可を受けていない(し、ロック・トークンも持っていない)ため です。しかし --force オプションを渡すと、認証と認可の 要求は無視され、他の人によって作成されたロックは解除されます。
もちろん単にロックを解除するだけでは十分ではないでしょう。上記の例では Sally は Harry がずっと長いこと忘れていたロックを解除したいだけではなく 自分自身の作業のためにそのファイルを再ロックしたいのが普通でしょう。 svn unlock --forceのあとで svn lockを実行すれ ばうまくいきます。しかし、この二つのコマンドの間に誰か別の人がロックして しまうわずかな可能性があります。もっと簡単な方法はロックを 横取りする(steal)ことであり、これはロック解除と 再取得を不分割な一まとまりの処理として実行します。これには svn lockに --forceオプションを 指定します:
$ 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'.
ロックを解除しようと横取りしようと、Harry はびっくりするかも知れません。 Harry の作業コピーにはまだ最初にロックを取得したときのロック・トークンがある のにロックそのものはもう存在していないからです。そのロック・トークンは 無効になった(defunct)と言います。 そのロック・トークンによって表されているロックは解除されたか(すでに リポジトリに存在していない)、横取りされたか(別のロックに置き換わった) のいずれかです。どちらの場合も Harry はリポジトリに対して svn statusコマンドを実行することで様子をつかむことが できます:
$ whoami harry $ svn status K raisin.jpg $ svn status --show-updates 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 での解決策は編集を始める前に ユーザにそのファイルをまずはロックすべきであることを思い起こしてもらうための 仕組みを提供することです。
この仕組みは特殊な属性をsvn:needs-lock用意することで 実現しています。この属性がファイルにつくと(この場合の属性値はどのようで あってもかまいません)、ファイルは読み込み専用のパーミッションを持つように なります。ユーザがファイルをロックし、ロック・トークンを取得するとファイルは 読み書き可能となります。ロックが解放されると—これは明示的にロック解放する かコミットを通じて自動的に解放されるかのどちらかですが— ファイルは再び 読み込み専用に戻ります。
こうすることで、画像ファイルにこの属性がついている場合、Sally は 編集のためにファイルを開いた時に何かおかしなことになっていることに すぐに気づくはずです。彼女が使っているアプリケーションはそのファイル が読み込み専用であることを伝えます。これで彼女は編集前にそのファイルを ロックしなくてはならないことを思いだし、こうして既に存在しているロック に気づくことになります:
$ /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: 2005-06-08 07:29:18 -0500 (Thu, 08 June 2005) Lock Comment (1 line): Making some tweaks. Locking for the next two hours.
「最良の方法」は、ユーザも管理者もお互いにマージすることが できないようなファイルには常に svn:needs-lock 属性をつけておくというものです。この技法はロック機能を利用する上での 良い習慣であり、無駄な作業を防ぐことができます。
この属性はロックシステムとは独立して機能するコミュニケーション用の 仕組みであることに注意してください。言いかえるとどのようなファイル も、このプロパティーがあるかどうかにかかわらずロックすることが できます。逆にこの属性の存在だけで、コミット時にリポジトリから常に ロックを要求されるということにはなりません。
これで完璧とはいきません。ファイルがこの属性を持っていたとしても 読み込み専用の警告機能が常に動作するとは限りません。アプリケーション の間違った動作によっては、警告を出さずに黙ってそのファイルに対する 編集を許し、保存してしまう結果、読み込み専用ファイルを「乗っ取って」 しまうこともあるでしょう。残念なことにこのような状況に対して Subversion ができることはあまり多くはありません。