ブランチの利用

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

For this chapter, we'll go back to the same example from 第1章. Remember that you and your collaborator, Sally, are sharing a repository that contains two projects, paint and calc. Notice that in 図 4.2. 「リポジトリレイアウトの開始」, however, each project directory now contains subdirectories named trunk and branches. The reason for this will soon become clear.

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

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

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

Let's say that you've been given the task of implementing radical new project feature. It will take a long time to write, and will affect all the files in the project. The problem here is that you don't want to interfere with Sally, who is in the process of fixing small bugs here and there. She's depending on the fact that the latest version of the project (in /calc/trunk) is always usable. If you start committing your changes bit-by-bit, you'll surely break things for 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.

And now here's the easier method of creating a branch, which we should have told you about in the first place: svn copy is able to operate directly on two URLs.

$ 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.

From the repository's point of view, there's really no difference between these two methods. Both procedures create a new directory in revision 341, and the new directory is a copy of /calc/trunk. This is shown in 図 4.3. 「新しいコピーのあるリポジトリ」. Notice that the second method, however, performs an immediate commit in constant time. [21] It's an easier procedure, because it doesn't require you to check out a large portion of the repository. In fact, this technique doesn't even require you to have a working copy at all. This is the way most users create branches.

図 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.

There's nothing special about this working copy; it simply mirrors a different directory in the repository. When you commit changes, however, Sally won'tsee them when she updates, because her working copy is of /calc/trunk. (Be sure to read ブランチの横断項 later in this chapter: the svn switch command is an alternate way of creating a working copy of a branch.)

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

  • /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 -v 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 -v 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での変更を見ることができるのは そのためです。

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

There are two important lessons that you should remember from this section. First, Subversion has no internal concept of a branch—it only knows how to make copies. When you copy a directory, the resulting directory is only a 「branch」 because you attach that meaning to it. You may think of the directory differently, or treat it differently, but to Subversion it's just an ordinary directory that happens to carry some extra historical information. Second, because of this copy mechanism, Subversion's branches exist as normal filesystem directories in the repository. This is different from other version control systems, where branches are typically defined by adding extra-dimensional 「labels」 to collections of files.



[21] Subversion does not support copying between different repositories. When using URLs with svn copy or svn move, you can only copy items within the same repository.