ブランチの利用

これまでのところで、それぞれのコミットがどうやってリポジトリに完全に新しい ファイルシステムツリー(「リビジョン」と呼ばれます)を作るかを知っていると思います。 まだ知らないのであれば、戻ってリビジョンに関するリビジョン項を 読んでください。

この章では、第2章と同じ例を使います。同僚のSally とあなたが paintcalcという 二つのプロジェクトのあるリポジトリを共有していたことを思い出して ください。しかし、図 4.2. 「リポジトリレイアウトの開始」を見ると、個々の プロジェクトディレクトリはtrunkbranchesというサブディレクトリを含んでいること に注意してください。この理由はすぐに明らかになります。

図 4.2. リポジトリレイアウトの開始

リポジトリレイアウトの開始

以前と同様、あなたと Sally はそれぞれ 「calc」 プロジェクトの作業コピーを持っているとします。特に両者はそれぞれ /calc/trunkの作業コピーを持っています。 プロジェクトのすべてのファイルは /calcに ではなくこのサブディレクトリ中にありますが、それは皆が開発の「主系」 を /calc/trunkに置くことに決めたからです。

あなたはプロジェクトの大胆な再編成を任されたとします。 それには長い時間が必要で、プロジェクトの全ファイルに影響 を与えます。問題はあなたは Sally に干渉したくない ということにあります。彼女はまだあちこちにある小さなバグを 潰している最中だからです。彼女はプロジェクトの最終バージョンが (これは/calc/trunkにあるのですが) 利用可能だということに依存しています。もし、あなたが自分の 変更をちょっとづつコミットすれば、Sallyの作業を確実に中断させて しまうでしょう。

一つのやり方として、閉じこもってしまう方法があります:あなたと Sallyは1,2週間、情報を共有するのをやめます。つまり、自分の 作業コピー中の全ファイルに対する大手術を始めるのですが、 それが完了するまで、コミットも更新もしないという方法です。 しかしこれにはいろいろな問題があります。まず安全ではありません。 ほとんどの人は、作業コピーにヘンなことが起こらないように、 リポジトリに対してこまめに自分の作業を保存するのを好みます。 次に、まったく柔軟ではありません。もし、あなたがたが別の マシンで仕事をしているなら、(多分二つの別のマシンに /calc/trunk の作業コピーがあるのでしょう) 自分の変更を手であちこちにコピーしなくてはならないか、 一つのマシン上に作業全体をフルコピーするかになります。 同じようにして他の誰との間でも自分の進行中の変更部分を共有する ことは困難です。通常のソフトウェア開発で「一番よいやり方」 はあなたの作業の進行状況を他の人からも参照できるようにすることです。 もしあなたの中間的なコミットを誰も見ることができないとすると あなたは他の人からフィードバックしてもらうことができなくなって しまいます。 最終的に自分の変更作業が完了したとき、その変更を コミットするのは非常に困難であることに気づくでしょう。Sally(と 他のメンバー)はリポジトリに対してたくさんの別の変更を加えており、 それをあなたの作業コピーにマージするのは困難です— 何週間も孤立した作業の後にsvn updateを実行する ような場合には特にそうです。

もっとましなやり方はリポジトリに自分用のブランチ、あるいは 自分用の作業の別ラインを作ることです。これは他の人に干渉 せずに、自分の中途半端な作業をときどき保存できるように しますが、それでも同僚との間で、一部の情報については共有する ことができます。どうやったらこんなことができるかは後で説明 します。

ブランチの作成

ブランチの作成はとても簡単です — svn copy コマンドでリポジトリ中のプロジェクトをコピーするだけです。 Subversionでは一つのファイルをコピーするだけでなく、ディレクトリ 全体をコピーすることができます。今回は、/calc/trunk ディレクトリのコピーがほしいでしょう。新しいコピーはどこに置けば 良いのでしょう? 好きな場所に置けます — あとはプロジェクトのポリシーに よります。チームのポリシーは、リポジトリの/calc/branches 領域にブランチを作ることで、ブランチ名は 「my-calc-branch」 としましょう。この場合、/calc/trunkのコピーとして、 /calc/branches/my-calc-branchという新しいディレクトリ を作る必要があります。

コピーを作るには、二つの方法があります。面倒な方法を最初に 説明して、概念をはっきりさせます。最初にプロジェクトのルートディレクトリ である /calcを作業コピーにチェックアウトします:

$ svn checkout http://svn.example.com/repos/calc bigwc
A  bigwc/trunk/
A  bigwc/trunk/Makefile
A  bigwc/trunk/integer.c
A  bigwc/trunk/button.c
A  bigwc/branches/
Checked out revision 340.

あとは、 svn copyコマンドに作業コピーパスを 二つ渡すだけでコピーを作れます:

$ cd bigwc
$ svn copy trunk branches/my-calc-branch
$ svn status
A  +   branches/my-calc-branch

この場合、svn copy コマンドは再帰的に trunk作業ディレクトリの内容を 新しい作業ディレクトリbranches/my-calc-branch にコピーします。svn status コマンドで 確認できますが、これで新しいディレクトリはリポジトリへの追加として 予告されます。ただ、Aの後に、「+」サインが表示されるのに注意して ください。これは、追加予告が、新規のものではなく、何かの コピー であることを示しています。 変更をコミットすると、Subversionは、ネットワーク越しに 作業コピーデータの全体を再送信するのではなく、 /calc/trunkをコピーすることで リポジトリに /calc/branches/my-calc-branch を作ります:

$ svn commit -m "Creating a private branch of /calc/trunk."
Adding         branches/my-calc-branch
Committed revision 341.

さて、ブランチを作るもっと簡単な方法は、先に説明すべきでした が: svn copy は 引数に直接URLを二つとることが できるということです。

$ svn copy http://svn.example.com/repos/calc/trunk ¥
           http://svn.example.com/repos/calc/branches/my-calc-branch ¥
      -m "Creating a private branch of /calc/trunk"

Committed revision 341.

この二つの方法には何の違いもありません。 両方とも新しいリビジョン341のディレクトリを作り、新しい ディレクトリは/calc/trunkのコピーに なります。図 4.3. 「新しいコピーのあるリポジトリ」にこれを示しました。 ただし二番目の方法は同時に コミットも発行します。 [8] 二番目のほうが楽です。リポジトリの 大きなコピーをチェックアウトしなくていいからです。 実際、この方法では、作業コピーそのものを用意する必要 すらありません。

図 4.3. 新しいコピーのあるリポジトリ

新しいコピーのあるリポジトリ

自分用のブランチでの作業

これでプロジェクトにブランチを作ることができたので それを使った新しい作業コピーをチェックアウトできます:

$ svn checkout http://svn.example.com/repos/calc/branches/my-calc-branch
A  my-calc-branch/Makefile
A  my-calc-branch/integer.c
A  my-calc-branch/button.c
Checked out revision 341.

この作業コピーについては何も特別なことはありません。単に 別のディレクトリにあるリポジトリのコピーだというだけです。 ただし、あなたが変更をコミットして、その後にSallyが更新しても その変更を見ることはありません。彼女の作業コピーは、 /calc/trunkからのものだからです。 (この章の作業コピーの切り替え項を読んでください: svn switchコマンドはブランチの作業コピー を作る別の方法です。)

一週間が経過する間に、以下のコミットが起こったとしましょう:

  • /calc/branches/my-calc-branch/button.c, に変更を加え、リビジョン342を作った。

  • /calc/branches/my-calc-branch/integer.c, に変更を加え、リビジョン343を作った。

  • Sallyは /calc/trunk/integer.cに 修正を加え、リビジョン344を作った。

これで、図 4.4. 「あるファイルの履歴のブランチ化」に示すように integer.cに二つの独立した開発ラインができました:

図 4.4. あるファイルの履歴のブランチ化

あるファイルの履歴のブランチ化

integer.cのコピーに起きた変更履歴を 見ると面白いことがわかります:

$ pwd
/home/user/my-calc-branch

$ svn log --verbose integer.c
------------------------------------------------------------------------
r343 | user | 2002-11-07 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
   M /calc/branches/my-calc-branch/integer.c

* integer.c:  frozzled the wazjub.

------------------------------------------------------------------------
r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
   A /calc/branches/my-calc-branch (from /calc/trunk:340)

Creating a private branch of /calc/trunk.

------------------------------------------------------------------------
r303 | sally | 2002-10-29 21:14:35 -0600 (Tue, 29 Oct 2002) | 2 lines
Changed paths:
   M /calc/trunk/integer.c

* integer.c:  changed a docstring.

------------------------------------------------------------------------
r98 | sally | 2002-02-22 15:35:29 -0600 (Fri, 22 Feb 2002) | 2 lines
Changed paths:
   M /calc/trunk/integer.c

* integer.c:  adding this file to the project.

------------------------------------------------------------------------

Subversion はブランチにあるinteger.cの履歴を 時間を逆向きにたどり、これにはコピーされた地点も含まれることに注意 してください。それはブランチの生成を履歴上の一つのできごととして 表示しますが、それはinteger.c/calc/trunk/全体がコピーされたときに暗黙に コピーされたものだからです。今度は Sally が自分のファイルコピー上 で同じコマンドを実行した結果を見てみましょう:

$ pwd
/home/sally/calc

$ svn log --verbose integer.c
------------------------------------------------------------------------
r344 | sally | 2002-11-07 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
   M /calc/trunk/integer.c

* integer.c:  fix a bunch of spelling errors.

------------------------------------------------------------------------
r303 | sally | 2002-10-29 21:14:35 -0600 (Tue, 29 Oct 2002) | 2 lines
Changed paths:
   M /calc/trunk/integer.c

* integer.c:  changed a docstring.

------------------------------------------------------------------------
r98 | sally | 2002-02-22 15:35:29 -0600 (Fri, 22 Feb 2002) | 2 lines
Changed paths:
   M /calc/trunk/integer.c

* integer.c:  adding this file to the project.

------------------------------------------------------------------------

Sallyは自分のリビジョン344の変更を見ることができますが、あなたが リビジョン343にやった変更は見ることができません。Subversionでは、 この二つのコミットはリポジトリの別の場所にある別のファイルに 対して起こります。しかし、Subversionは、二つのファイルが共通の履歴を 持っていることを示してもいます。リビジョン341 で起きたブランチコピーの前は両者は同じファイルを使っていました。 Sallyとあなたがどちらもリビジョン 303と98での変更を見ることができるのは そのためです。

ブランチの背後にある鍵となる考え方

この節での重要事項は二つです。

  1. 他のたくさんのバージョン管理システムとは違ってSubversionの ブランチはリポジトリ中の普通のファイルシステム のディレクトリ として存在します。特別な仕組みが あるわけではありません。これらのディレクトリは単にある特別な 履歴情報も保持しているというだけのことです。

  2. Subversionは内部的にはブランチという概念を持ちません —それはただのコピーです。ディレクトリをコピーした とき、結果としてできたディレクトリが「ブランチ」であるのは、 あなたが そのような意味で見ることに したからです。そのディレクトリを別の意味合いにとらえたり 取り扱ったりすることもできますが、いずれにせよSubversionに とっては、コピーによって作成された普通のディレクトリの 一つにすぎません。



[8] Subversion はリポジトリ間コピーをサポートしていません。svn copysvn moveで URLを指定する場合、 同じリポジトリ内でのみコピーすることができます。