Subversion の動作

さて、そろそろ抽象論から具体的な議論に移りましょう。本節では Subversion が利用される実例をお見せします。

Subversion リポジトリの URL

本書を通じて、Subversion リポジトリのバージョン管理下のファイルやディレクトリを特定するため、Subversion は URL を使います。ほとんどの場所で、サーバ名とポート番号を URL の一部として指定することができる、以下のような URL の標準的な構文を利用しています。

$ svn checkout http://svn.example.com:9834/repos
…

But there are some nuances in Subversion's handling of URLs that are notable. For example, URLs containing the file:// access method (used for local repositories) must, in accordance with convention, have either a server name of localhost or no server name at all:

$ svn checkout file:///path/to/repos
…
$ svn checkout file://localhost/path/to/repos
…

Also, users of the file:// scheme on Windows platforms will need to use an unofficially 「standard」 syntax for accessing repositories that are on the same machine, but on a different drive than the client's current working drive. Either of the two following URL path syntaxes will work where X is the drive on which the repository resides:

C:¥> svn checkout file:///X:/path/to/repos
…
C:¥> svn checkout "file:///X|/path/to/repos"
…

In the second syntax, you need to quote the URL so that the vertical bar character is not interpreted as a pipe. Also, note that a URL uses forward slashes even though the native (non-URL) form of a path on Windows uses backslashes.

注意

Subversion's file:// URLs cannot be used in a regular web browser the way typical file:// URLs can. When you attempt to view a file:// URL in a regular web browser, it reads and displays the contents of the file at that location by examining the filesystem directly. However, Subversion's resources exist in a virtual filesystem (see リポジトリ層項), and your browser will not understand how to interact with that filesystem.

最後に、Subversion クライアントは必要に応じて、ちょうど Web ブラウザがや るような具合に自動的に URL をエンコードすることにも注意してください。 たとえば、URL が空白あるいは ASCII の範囲外の文字が含まれている場合、以下のようになります。

$ svn checkout "http://host/path with space/project/españa"

… Subversion は安全に表示できる文字に変換して、以下のように、元々そのように入力したかのように動作します。

$ svn checkout http://host/path%20with%20space/project/espa%C3%B1a

URL が空白を含む場合、引用符で囲んであるか確認してください。これでシェルは、svnプログラムに対して、その文字列全体が一つの引数であるものとして扱うことができるようになります。

作業コピー

既に作業コピーについて読んできたことと思いますので、Subversionのクライアント プログラムが作業コピーを作ったり使ったりする様子を見てみます。

Subversion 作業コピーは、自分のローカルシステム上の普通の ディレクトリツリーで、その中には複数のファイルがあります。あなたは 望むファイルを編集することができ、ソースコードファイルなら、それを 普通にコンパイルすることができます。作業コピーは自分だけの作業領域 です: Subversion はほかの人の変更を持ち込んだりしませんし、明示的に そうしてくれと言うまで、自分の変更を他の人に見せたりすることも ありません。同じプロジェクト用に一人で複数の作業コピーを持つことさえできます。

作業コピーのファイルに変更を加え、それがうまく動作することを 確認したあとで、Subversion はその変更を同じプロジェクトであなたと一緒に 作業しているほかの人に「公開」するためのコマンドを(リポジトリに 書き込むことで)用意します。もし他の人が自分自身の変更を公開したとき にはSubversionはその変更を自分の作業コピーにマージするコマンドを用意します。 (リポジトリの内容を読み出すことで。)

作業コピーには、Subversionによって管理される、いくつかの特殊な ファイルもあり、その助けによって(読み出し、書き込みなどの)コマンドを 実行します。特に作業コピー中のディレクトリには.svn という名前の、管理ディレクトリとして知られる サブディレクトリがあります。管理ディレクトリのそれぞれのファイルは Subversionがどのファイルにまだ公開していない変更があるか、どのファイルが 他の人の作業によって最新でなくなっているか理解するのを助けるものです。

典型的な Subversion リポジトリは複数のプロジェクトのファイル (またはソースコード)をつかんでいます。普通、それぞれのプロジェクトは リポジトリのファイルシステムツリー中のサブディレクトリになっています。 この構成によって、ユーザの作業コピーは普通、リポジトリの特定の 部分木に対応しています。

たとえば二つのソフトウェアプロジェクト、paintcalcを含むリポジトリが あるとします。それぞれのプロジェクトはそれぞれの最上位サブディレクトリ にあります。図 1.6. 「リポジトリのファイルシステム」のような状況です。

図 1.6. リポジトリのファイルシステム

リポジトリのファイルシステム

作業コピーを持ってくるため、リポジトリ中のどれかのサブツリーを チェックアウトしなくてはなりません。 (「check out」 という言葉は何かをロックしたり保護したり するような響きがありますがそうではありません; それは単に自分のための プロジェクトのコピーを作るだけです。) たとえば/calcをチェックアウトするとこんな 感じで作業コピーを手に入れることができます:

$ svn checkout http://svn.example.com/repos/calc
A    calc/Makefile
A    calc/integer.c
A    calc/button.c
リビジョン 56 をチェックアウトしました。

$ ls -A calc
Makefile  integer.c  button.c  .svn/

The list of letter A's in the left margin indicates that Subversion is adding a number of items to your working copy. You now have a personal copy of the repository's /calc directory, with one additional entry—.svn—which holds the extra information needed by Subversion, as mentioned earlier.

Suppose you make changes to button.c. Since the .svn directory remembers the file's original modification date and contents, Subversion can tell that you've changed the file. However, Subversion does not make your changes public until you explicitly tell it to. The act of publishing your changes is more commonly known as committing (or checking in) changes to the repository.

変更点を他の人に公開するには、Subversion の commit コマンドを使用します。

$ svn commit button.c -m "Fixed a typo in button.c."
Sending        button.c
Transmitting file data .
Committed revision 57.

Now your changes to button.c have been committed to the repository, with a note describing your change (namely, that you fixed a typo). If another user checks out a working copy of /calc, they will see your changes in the latest version of the file.

一緒に作業している Sally が、あなたがチェックアウトしたのと同じ時刻に /calc の作業コピーを自分用にチェックアウト したとしましょう。あなたがbutton.cへの自分の 変更をコミットしても、Sallyの作業コピーは変更されない状態のままです。 Subversionはユーザの要求によって初めて作業コピーの内容を変更します。

作業内容をプロジェクトの最新の状態にするには、SallyはSubversionに 自分の作業コピーを更新 するように依頼しなくては なりません。これにはupdate コマンドを使います。 これはあなたの変更を彼女の作業コピーにマージしますし、彼女がチェック アウトしたあとで他の人がコミットしたすべての部分についてもマージします。

$ pwd
/home/sally/calc

$ ls -A 
.svn/ Makefile integer.c button.c

$ svn update
U    button.c
Updated to revision 57.

svn updateコマンドからの出力は Subversionがbutton.cの内容を 更新したことを示しています。Sally はどのファイルを更新 するかを指定する必要がないのに注意してください。Subversion は .svnディレクトリの情報と リポジトリの情報を使って、どのファイルを更新しなくてはならないか を決定します。

リビジョン

svn commit 操作は不可分トランザクションとして任意の数のファイル、ディレクトリに対する変更点を公開できます。作業コピー中で、ファイルの内容を変えたり、新しいファイルを作ったり、削除したり、名前を変えたり、ファイルやディレクトリをコピーしたあと、それらの変更点の全体を完全なひとかたまりのものとしてコミットすることができます。

By 「atomic transaction」, we mean simply this: either all of the changes happen in the repository, or none of them happen. Subversion tries to retain this atomicity in the face of program crashes, system crashes, network problems, and other users' actions.

リポジトリがコミットを受け付けるときは常に リビジョンと呼ばれるファイルシステム ツリーの新しい状態を作ります。それぞれのリビジョンには 一意な自然数が割り当てられます。前のバージョンよりも 後のバージョンのほうが数が大きくなります。 リポジトリ新規作成時の最初のバージョンはゼロで、ルートディレクトリ 以外には何も含まれていません。

図 1.7. 「リポジトリ」 はリポジトリを視覚化するうまい方法 を示しています。0から始まるリビジョン番号が、左から右に追加されていく 状況を想像してください。それぞれのリビジョン番号には対応した ファイルシステム木があり、それぞれの木はコミット 後のリポジトリの状態を示す「スナップショット」 です。

図 1.7. リポジトリ

リポジトリ

作業コピーは常にリポジトリのどれか一つのリビジョン対応しているとは 限らないことに注意してください。複数の異なるリビジョンのファイル を含んでいるかも知れません。たとえば、最新リビジョン番号が4である リポジトリから作業コピーをチェックアウトしたとします:

calc/Makefile:4
     integer.c:4
     button.c:4

この時点では、作業コピーはリポジトリのリビジョン4と完全に一致しています。 しかし、ここで button.cに変更を加え その変更をコミットしたとします。他にコミットした人がいない場合、 今回のコミットはリポジトリのバージョンを5にあげ、作業コピーの内容は 以下のようになります:

calc/Makefile:4
     integer.c:4
     button.c:5

この時点でSallyがinteger.cに対する修正を コミットし、リビジョンを6にあげたとします。ここでもし、svn update コマンドであなたの作業コピーを更新すると、次のようになるでしょう:

calc/Makefile:6
     integer.c:6
     button.c:6

Sallyのinteger.cへの変更は あなたの作業コピーに現れますが、button.c に対するあなたの変更はそのままです。この例では、 Makefileのテキストは、リビジョン4,5,6で まったく同一のものですが、Subversionはあなたの作業コピー中の Makefileのリビジョンを6として、 それが最新であることを表現します。それで自分の作業コピーに きれいなアップデートをかけたときには、一般に作業コピーは リポジトリのある特定のバージョンと完全に一致します。

作業コピーはどのようにリポジトリを追いかけるか

作業コピー中のそれぞれのファイルについて、Subversionは 二つの本質的な情報を.svn/管理領域に 記録します:

  • あなたの作業ファイルは、どのリビジョンに基づいているか (これはファイルの作業リビジョンと呼ばれます)、 そして

  • リポジトリとの対話によって作業コピーが最後に更新された時刻

これらの情報とリポジトリとの対話によって、Subversionは作業ファイルの それぞれが、以下の四つの状態のどれにあるかを見分けることができます:

変更なし、かつ最新

作業コピーのファイルは変更されていないし、その作業リビジョン 以降に起きたリポジトリに対するコミットでもそのファイルに対する変更が ない状態。 そのファイルに対するsvn commitは何も実行しませんし、 svn updateも何もしません。

ローカルで変更あり、かつ最新

The file has been changed in the working directory, and no changes to that file have been committed to the repository since you last updated. There are local changes that have not been committed to the repository, thus an svn commit of the file will succeed in publishing your changes, and an svn update of the file will do nothing.

変更なし、かつ、最新ではない

The file has not been changed in the working directory, but it has been changed in the repository. The file should eventually be updated, to make it current with the latest public revision. An svn commit of the file will do nothing, and an svn update of the file will fold the latest changes into your working copy.

ローカルで変更あり、かつ最新ではない

ファイルは作業コピーでも、リポジトリでも変更されています。 ファイルに対する svn commit は 「out-of-date」 エラーになります。そのファイルはまず更新しなくてはなりません。 ファイルに対する svn update は公開されている変更点 を作業コピーの変更にマージしようとします。これが自動的にできないような状況の場合、Subversionはユーザに競合の解消をさせるためそのままにしておきます。

これにはいろいろな情報の変化を追う必要があるように思いますが、 svn status コマンドを使えば、あなたの作業コピーの どのファイルの状態も表示できます。このコマンドについてのより詳しい情報は 自分がした変更の概要確認項 を見てください。

混合リビジョン状態の作業コピー

原則として、Subversionはできる限り柔軟であろうとします。 この特別な例として、作業コピーに、いろいろな異なる作業リビジョン番号を もったファイルとディレクトリを共存させることが できます。前の例での混合リビジョンに戸惑っている人のために、 なぜこのような機能が必要で、どのように利用したらよいかを以下に示します。

更新とコミットは別の処理です

Subversion での基本的な原則の一つは、「作業コピーへの取得(push)」の動作 が「リポジトリへの反映(pull)」動作を自動的に引き起こすことは ないし、逆もないということです。これは、あなたがリポジトリへの新しい変更点を 送信する用意ができているということが、他の人たちの変更点を受け取る用意が できていることを意味していることはないという、当たり前の理由によります。 そして自分がまだ引き続き新しい修正を加えている場合、 svn update は自分自身の作業コピー中にリポジトリの内容をうまく反映してくれるはずで、 このさい、あなたの側の変更点を強制的に他の人々に公開する必要はありません。

この規則はまた副次的に、作業コピーには混合リビジョンの状態を記録する ための特殊な仕組みが必要になり、またその状態に対して寛容でなければならない ことを意味しています。これはディレクトリ自身もバージョン管理できる ためさらに複雑な話になります。

たとえば、作業コピーが完全にリビジョン 10 にあるとします。foo.html を編集してsvn commitを実行した結果、リポジトリにリビジョン 15 ができたとします。このコミットが成醐サ駈オた直後では、多くの不慣れなユーザは 作業コピーは完全にリビジョン 15 にあるだろうと期待するかも知れませんがそうでは ないのです!。リビジョン10 とりビジョン15 までの間にリポジトリに対していろいろな変更が 起こったかも知れないのです。クライアント側ではリポジトリに起きたこの変更については 何も知りません。まだ svn update を実行していませんし、 svn commit は新しい変更点をリポジトリから取得したりはしないからです。 一方、もしかりにsvn commitが自動的に最新の変更点をダウンロード するとすれば、作業コピー全体を完全にリビジョン 15 に設定することも可能 でしょう—しかしこれでは「push」と「pull」 が独立した処理であるという基本的な原則を侵すことになります。 このため Subversion クライアントができる唯一の安全な方法は、ある特定の ファイル—foo.html—がリビジョン 15 にある という印をつけることだけです。作業コピーの残りのファイルはリビジョン 10 の ままなのです。svn updateを実行することだけが、最新の変更点 をダウンロードする方法であり、これで作業コピー全体にリビジョン 15 の印がつきます。

混合リビジョンは正常な状態です

事実として、svn commitを実行するときは 常に、あなたの作業コピーはあるいくつかのリビジョンの 混合状態となります。コミット対象となったファイルだけは、それ以外のファイル よりも新しい作業リビジョンになります。何度かのコミットの後で( その間に update を含めなければ)、作業コピーはいくつかのリビジョンの 混合状態になります。あなたがリポジトリを利用している唯一のユーザであったと してもやはりこの現象に出会うでしょう。作業リビジョンの混合状況を見る にはsvn status --verboseコマンドを利用して ください(さらに詳しい情報については 自分がした変更の概要確認項を見てください)。

不慣れなユーザは自分の作業コピーが混合リビジョンになっていることには まったく気づかないことがよくあります。多くのクライアントコマンドは 処理対象となるアイテムの作業コピー上でのリビジョンが問題になるので 混乱することになります。例えばsvn logコマンドは ファイルあるいはディレクトリの変更履歴を表示するために利用されます (変更履歴の一覧生成項参照)。ユーザがこのコマンド を作業コピー上野オブジェクトに対して実行するとき、そのオブジェクト の完全な履歴を見れるものだと考えるでしょう。しかしそのオブジェクトの 作業コピー上のりビジョンが非常に古いものであった場合(これは svn updateが長い期間にわたって実行されなかったような 場合におこります)、そのオブジェクトの より古い バージョン履歴が表示されるでしょう。

混合リビジョンは役にたつものです

If your project is sufficiently complex, you'll discover that it's sometimes nice to forcibly backdate (or, update to a revision older than the one you already have) portions of your working copy to an earlier revision; you'll learn how to do that in 第2章. Perhaps you'd like to test an earlier version of a sub-module contained in a subdirectory, or perhaps you'd like to figure out when a bug first came into existence in a specific file. This is the 「time machine」 aspect of a version control system—the feature which allows you to move any portion of your working copy forward and backward in history.

混合リビジョンには制約があります

作業コピー中を混合リビジョン状態に置くことはできますが、 この柔軟性には制約があります。

まず、完全に最新状態ではないファイルやディレクトリの削除を コミットすることができません。より新しいバージョンのアイテムが リポジトリに存在する場合、この試みは拒否されます。まだあなたが 見ていない変更点を間違って消してしまうことを防ぐためです。

Second, you cannot commit a metadata change to a directory unless it's fully up-to-date. You'll learn about attaching 「properties」 to items in 第3章. A directory's working revision defines a specific set of entries and properties, and thus committing a property change to an out-of-date directory may destroy properties you've not yet seen.