[目次へ][7章へ][7.1へ][7.3へ] 最終更新:$Date: 2002/09/09 05:29:03 $

WinCvsのXP画面撮りなおし。


■■ 7.2 ブランチについて考える
■■■ 7.2.1 ブランチを作ると何がうれしいの?
■■■ 7.2.2 ブランチを作るには
■■■ 7.2.3 ブランチを取り出すには
■■■ 7.2.4 ブランチで作業するには
■■■ 7.2.5 マージしてみる
■■■ 7.2.6 WinCvsでのブランチ


■■7.2 ブランチについて考える

タグのところで少し紹介しましたが、ブランチタグという特殊なタグをつけることで、CVSの管理するリビジョン情報にブランチ(枝)を作ることができます。ブランチというのは、トランク(幹)と呼ばれるメインのリビジョンに対して、そこから分岐してできたリビジョンのことです。イメージ的には【図7.2.1】のようになります。

【図7.2.1】ブランチのイメージ

この図は、BTAGというブランチタグをつけてブランチを作ったあと、ブランチとトランクが並行してリビジョンを進めていく様子を表しています。分岐した後はお互いの変更は全く影響しません。と言われてもぴんとこないかと思いますので、もうちょっと具体的に説明してみましょう。

■■■7.2.1 ブランチを作ると何がうれしいの?

プログラム開発をしているときはうれしいです(ソースコード以外の文書ではあまり嬉しさはないかもしれません)。

どういうことかというと、プログラムを開発していると、時折すばらしいことを思いついて、ソースコードに組み込みたくなります。あるいは、開発を依頼した人の要求で新しい機能の追加を強いられることがあるかもしれません。何にしろ、今動いているプログラムに新しい機能を組み込むときは、一旦プログラムが不安定になってしまうということがよくあります。つまり、新しいコードが他の部分となじむまでに時間がかかるのです(なじまないと、バグという形で色々な不快な現象が起こります)。一方、今動いているプログラムは安定してはいるものの、やはりちょっとした不都合が残っていて、修正の必要があるかもしれません。新しい機能を追加したプログラムの方でその不都合を解決しても、それが安定して提供されるまで待っていたら、その恩恵を受けるまでに時間がかかりすぎでしまいます。

このため、プログラムが安定動作するまで、新しいソースコード群と、多くの人が使っている安定版のソースコード群とは分離され、かつ並行して開発が続けられなければなりません。そして、新しいプログラムが安定したら、バグ取りが続けられてきた安定版のソースコードと合わせて、新しい安定版のプログラムとして提供されることになります。

ブランチはこのようなときに、安定版のソースコード群と、開発用のソースコード群を分離ために用います。どちら側をトランクとするかは、微妙なところです。しばらく考えてみたのですが、安定版はいずれ成長が止まるので、安定版をブランチとして分離してバグフィックスだけとする一方、トランクを開発版として新機能追加をがんがんやっていくというのが一般的かもしれません。Red Hat LinuxやFreeBSDなど多くのオープンソースのの開発では、安定版と開発版のそれぞれに特有のバージョン番号がついて運用されています。

トランクも特殊なブランチの一種と言えないこともありません。ブランチもトランクもそれぞれ並行してバージョン管理されますが、実際には1つの,vファイルで管理されているので、ブランチのリビジョン番号とトランクのリビジョン番号が,vファイルの中に入り混じっています。

実際に分岐したブランチの取扱いですが、ブランチ側のプログラムが安定したらトランクへとマージし、そのブランチを破棄する方法と、開発用のブランチとして何回も再利用しつつ適当なタイミングでトランクにマージするという2つの方法があります。トランクへのマージが繰り返されない分、前者の方が後者より簡単です。この他ブランチの運用方法については、より詳しい文献(「CVSバージョン管理システム」など)をあたると良いでしょう。

■■■7.2.2 ブランチを作るには

ブランチを作るには、tagコマンドあるいはrtagコマンドの-bオプションを使用します。rtagコマンドの場合、操作対象とするリポジトリと、どのリビジョン、あるいはどの時点でブランチタグをつけるのかという、分岐点を指定する必要があります【図7.2.2】。

【図7.2.2】ブランチ作成の書式(rtagを使った場合)
▼
cvs -d リポジトリ rtag -r リビジョン(-D 日付) -b ブランチタグ名 ファイル群...
▲

なお、tagコマンドでもリビジョン・日付を指定することができます【図7.2.3】。省略すると現時点につけるということになります。

【図7.2.3】ブランチ作成の書式(tagを使った場合)
▼
cvs tag [-r リビジョン| -D 日付] -b ブランチタグ名 ファイル群...
▲

簡単な例を使って説明してみましょう。branchtestという3つのファイルからなるモジュールを作って登録してみます【図7.2.4】。

【図7.2.4】branchtestの登録
▼
% ls
b1.txt  b2.txt  b3.txt
% cvs -d /home/cvsroot import -m "Branch test module." branchtest mikamama BRANCHTEST_1
N branchtest/b1.txt
N branchtest/b2.txt
N branchtest/b3.txt

No conflicts created by this import
▲

このモジュールのファイルに対して、何回か編集・コミットを繰り返してみます。タグをつける時点でb1.txtは1.3、b2.txtは1.2、b3.txtは1.4という版になっていると仮定します。この作業コピーの上で、tagコマンドを利用してブランチを作ってみます。ブランチタグ名はTESTBRANCH-1とつけることにしましょう。

まず、ブランチを作る時点で通常のタグをつけましょう。これは分岐点を後で取り出して比べたり、やりなおしたりしたくなることがあるためです。名前は何でもよいのですが、分岐点であるということがわかる名前をつけるのがよいと思います。ここでは、root-of-をブランチタグの頭につけたものを使うことにしましょう。ブランチタグ名をTESTBRANCH-1とすることにしましたので、分岐点のタグはroot-of-TASEBRABCH-1とします。1行目がその分岐点のタグ付けをしています【図7.2.5】。

【図7.2.5】ブランチ作成の前準備
▼
% cvs tag root-of-TESTBRANCH-1
cvs tag: Tagging .
T b1.txt
T b2.txt
T b3.txt
▲

次に、tagコマンドに-bオプションをつけてブランチタグをつけます【図7.2.6】。

【図7.2.6】いよいよブランチ作成
▼
% cvs tag -b TESTBRANCH-1
cvs tag: Tagging .
T b1.txt
T b2.txt
T b3.txt
▲

これだけでは、どんなタグがついたかわからないので、statusコマンドの-vオプションで各ファイルについたタグを眺めてみましょう【図7.2.7】。

【図7.2.7】どんなタグがついてるんだろう?
▼
% cvs status -v
cvs status: Examining .
===================================================================
File: b1.txt            Status: Up-to-date

   Working revision:    1.3     Thu Sep  5 14:32:27 2002
   Repository revision: 1.3     /home/cvsroot/branchtest/b1.txt,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)

   Existing Tags:
        TESTBRANCH-1                    (branch: 1.3.2)
        root-of-TESTBRANCH-1            (revision: 1.3)
        BRANCHTEST_1                    (revision: 1.1.1.1)
        mikamama                        (branch: 1.1.1)

===================================================================
File: b2.txt            Status: Up-to-date

   Working revision:    1.2     Thu Sep  5 14:30:56 2002
   Repository revision: 1.2     /home/cvsroot/branchtest/b2.txt,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)

   Existing Tags:
        TESTBRANCH-1                    (branch: 1.2.2)
        root-of-TESTBRANCH-1            (revision: 1.2)
        BRANCHTEST_1                    (revision: 1.1.1.1)
        mikamama                        (branch: 1.1.1)

===================================================================
File: b3.txt            Status: Up-to-date

   Working revision:    1.4     Thu Sep  5 14:30:56 2002
   Repository revision: 1.4     /home/cvsroot/branchtest/b3.txt,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)

   Existing Tags:
        TESTBRANCH-1                    (branch: 1.4.2)
        root-of-TESTBRANCH-1            (revision: 1.4)
        BRANCHTEST_1                    (revision: 1.1.1.1)
        mikamama                        (branch: 1.1.1)
▲

なんだか、Existing Tags:に沢山のタグが表示されましたね。はじめの2つが今つけたタグで、残りの2つがimportコマンド実行時につけたベンダータグ名(mikamama)と、リリースタグ名(BRANCHTEST_1)です。後半の2つは外部のベンダーからソースコードを提供されている場合に、新しく提供されたバージョンのソースコードと手元で変更したソースコードをマージしたいというような状況で使われます。このタグの使用法について詳しく知りたい場合は、「CVSバージョン管理システム」を読むと良いでしょう。

ここでは自分のつけた、分岐点タグroot-of-TESTBRANCH-1とブランチタグTESTBRANCH-1について詳しく見てみます。分岐点タグは通常のタグで、各ファイルのリビジョン1.3、1.2、1.4についています。おもしろいのは、ブランチタグに割り振られた1.3.2、1.2.2、1.4.2というリビジョン番号です。このようにブランチは3つの番号からなります。そして後で見るように、ブランチ上のリビジョンは4つの数字で表されます。つまり、次に変更をコミットするとそれぞれリビジョンは、1.3.2.1、1.4.2.1、1.2.2.1のようになります。

■■■7.2.3 ブランチを取り出すには

ブランチを取り出してその上で作業を開始するには、checkoutコマンド実行時に-rオプションを使ってブランチタグ名を指定します。

【図7.2.8】ブランチを取り出すための書式
▼
cvs -d リポジトリ checkout -r ブランチタグ名 モジュール名
▲

環境変数CVSROOTを設定していれば-dオプションは必要ありませんけどね。では、さっそく取り出してみましょう【図7.2.9】。以下では、作業場体を区別するために、プロンプトの表示をブランチ側での作業を[ブランチ]%、トランク側での作業を[トランク]%というように書くことにします。

【図7.2.9】ブランチを取り出す
▼
[ブランチ]% cvs -d /home/cvsroot checkout -r TESTBRANCH-1 branchtest
cvs checkout: Updating branchtest
U branchtest/b1.txt
U branchtest/b2.txt
U branchtest/b3.txt
▲

取り出した後、この作業コピーに移動し、status -vコマンドで状態を見てみます【図7.2.10】。長いので途中から省略しています。

【図7.2.10】ブランチの状態を見てみよう

▼
[ブランチ]% cvs status -v

cvs status: Examining .
===================================================================
File: b1.txt            Status: Up-to-date

   Working revision:    1.3     Thu Sep  5 14:32:42 2002
   Repository revision: 1.3     /home/cvsroot/branchtest/b1.txt,v
   Sticky Tag:          TESTBRANCH-1 (branch: 1.3.2)
   Sticky Date:         (none)
   Sticky Options:      (none)

   Existing Tags:
        TESTBRANCH-1                    (branch: 1.3.2)
        root-of-TESTBRANCH-1            (revision: 1.3)
        BRANCHTEST_1                    (revision: 1.1.1.1)
        mikamama                        (branch: 1.1.1)

===================================================================
File: b2.txt            Status: Up-to-date

   Working revision:    1.2     Thu Sep  5 14:32:54 2002
   Repository revision: 1.2     /home/cvsroot/branchtest/b2.txt,v
   Sticky Tag:          TESTBRANCH-1 (branch: 1.2.2)
(後略)
▲

すると、Stickyタグにブランチタグがついていることがわかります。以前Stickyタグが設定されているとコミットできなくなるといいましたが、ブランチタグの場合にはそういうことはありません。この場合のStickyタグはブランチだということを表すために設定されているだけで、通常通りコミットすることができます。

これまでの作業過程と各ファイルの変化を図で表すと、【図7.2.11】のようになります。

【図7.2.11】分岐するまでの作業の様子

■■■7.2.4 ブランチで作業するには

ブランチを取得してしまえば、その作業コピー上で作業している限り、トランクでの作業と変わりません。ややこしいのはマージする時です。マージについては7.2.5項で説明します。ちょっと、b1.txtを編集してコミットしてみましょう【図7.2.12】。

【図7.2.12】ブランチの方で変更をコミットする
▼
[ブランチ]% cvs commit -m "Branch first commit"
cvs commit: Examining .
Checking in b1.txt;
/home/cvsroot/branchtest/b1.txt,v  <--  b1.txt
new revision: 1.3.2.1; previous revision: 1.3
done
▲

ブランチ上のリビジョンは4つの数字で表されます。その前の3つの数字はブランチに割り振られた番号です。5行目で1.3から1.3.2.1に上がったというメッセージがあります。statusコマンドで見ると【図7.2.13】、リビジョンが1.3.2.1でブランチの番号が1.3.2であることがわかります。

【図7.2.13】コミット後の様子
▼
[ブランチ]% cvs status b1.txt
===================================================================
File: b1.txt            Status: Up-to-date

   Working revision:    1.3.2.1 Thu Sep  5 14:37:12 2002
   Repository revision: 1.3.2.1 /home/cvsroot/branchtest/b1.txt,v
   Sticky Tag:          TESTBRANCH-1 (branch: 1.3.2)
   Sticky Date:         (none)
   Sticky Options:      (none)
▲

ここで、他の場所に改めてこのブランチの作業コピーをとってみます 【図7.2.14】。

【図7.2.14】別の場所でブランチを取り出してみる
▼
[ブランチ2]% cvs -d /home/cvsroot checkout -r TESTBRANCH-1 branchtest
cvs checkout: Updating branchtest
U branchtest/b1.txt
U branchtest/b2.txt
U branchtest/b3.txt
▲

b1.txtのりビジョンはどうなっているのでしょうか【図7.2.15】。

【図7.2.15】b1.txtのりビジョンはどうなったんだろう
▼
[ブランチ2]% cvs status b1.txt
===================================================================
File: b1.txt            Status: Up-to-date

   Working revision:    1.3.2.1 Thu Sep  5 14:37:25 2002
   Repository revision: 1.3.2.1 /home/cvsroot/branchtest/b1.txt,v
   Sticky Tag:          TESTBRANCH-1 (branch: 1.3.2)
   Sticky Date:         (none)
   Sticky Options:      (none)
▲

Working revisionが1.3.2.1になっていますので、ブランチの最新バージョンが取り出されているようです。他の人が開発に加わった場合にもあまり気にしないで大丈夫ということですね。

■■■7.2.5 マージしてみる

ブランチはいつかはマージされる必要があります。マージしないでずっと独立して開発を続けていると、何か別のものになってしまいます(笑)。普通はトランクの内容とかけ離れてしまわないうちに、当初の目的である機能の組み込みが安定したらトランクに変更を組み込み、ブランチを放棄します。

放棄しない場合には、トランクに対しておこなわれた変更を自分の方に組み込んで一旦同じ状態にし、その後新しい機能の組み込みに挑戦します。前者の一番の欠点はトランクに旧ブランチがマージされて、新しい作業用ブランチができるまで、ブランチ側の開発者の作業が停滞するということです。後者の場合には、マージされている間もブランチ上で作業を続けることができます。しかし、トランク側でマージが終わった後、トランクの変更をブランチに反映させるのにちょっと手間がかかります。ここでは、簡単な例を使って、まずブランチからトランクへのマージ、その後のトランクからブランチへのマージについて眺めてみましょう。

一般的にマージには時間がかかります。これは、コンフリクト(conflict=競合)が発生する可能性があるからです。第1章で少し話しましたが、コンフリクトというのは、同じファイルの同じ場所を違った形で編集した場合に発生します。このような時、CVSは解決の手立てを持ちません。「コンフリクトが発生したので解決してね」という内容のメッセージと、コンフリクトした結果のファイルを開発者に残します。コンフリクトを解決するのは人間です。通常は、プログラム全体の行く末を把握している人が、コンフリクトを起こした部分を書いた開発者と話し合いながら、うまくいくように書き直します。

コンフリクトの簡単な例を考えてみます。分岐時点でのb1.txtが【図7.2.16】のようであったとします。

【図7.2.16】分岐時点でのb1.txt
▼
This is a branch test file No.1 b1.txt.
Second commit.
▲

これをブランチ側で、【図7.2.17】のように書き換えたとします。

【図7.2.17】ブランチ側b1.txt
▼
This is a branch test file No.1 b1.txt.
Second commit.
Branch first commit.
▲

さらに、トランク側で【図7.2.18】のように書き換えたとしましょう。3行目が相違点です。

【図7.2.18】トランク側b1.txt
▼
This is a branch test file No.1 b1.txt.
Second commit.
Conflict test.
▲

まず、トランク側でコンフリクトを起こすための変更をコミットしておきます【図7.2.18】。リビジョンは1.3から1.4に上がりました。

【図7.2.19】トランクの方で変更をコミットする
▼
[トランク]% cvs commit -m "Conflict test." b1.txt
Checking in b1.txt;
/home/cvsroot/branchtest/b1.txt,v  <--  b1.txt
new revision: 1.4; previous revision: 1.3
done
▲

ここで、トランク側にマージしようと思います。マージする前に、トランクでの修正を後からブランチに反映させることができるように、ブランチにタグを設定しておきます。次の開発期間に入ったということで、1つ数字をインクリメントしてタグ名をTESTBRANCH-2としましょう【図7.2.20】。

【図7.2.20】マージされる直前にブランチにタグをつける
▼
[ブランチ]% cvs tag TESTBRANCH-2
cvs tag: Tagging .
T b1.txt
T b2.txt
T b3.txt
▲

例えばb1.txtをstatusコマンドの-vオプションで見てみる【図7.2.21】と、ブランチのリビジョン1.3.2.1にTESTBRANCH-2がついていることがわかります。

【図7.2.21】タグの状態
▼
[ブランチ]% cvs status -v b1.txt
===================================================================
File: b1.txt            Status: Up-to-date

   Working revision:    1.3.2.1 Thu Sep  5 14:37:12 2002
   Repository revision: 1.3.2.1 /home/cvsroot/branchtest/b1.txt,v
   Sticky Tag:          TESTBRANCH-1 (branch: 1.3.2)
   Sticky Date:         (none)
   Sticky Options:      (none)

   Existing Tags:
        TESTBRANCH-2                    (revision: 1.3.2.1)
        TESTBRANCH-1                    (branch: 1.3.2)
        root-of-TESTBRANCH-1            (revision: 1.3)
        BRANCHTEST_1                    (revision: 1.1.1.1)
        mikamama                        (branch: 1.1.1)
▲

次に、トランクへマージするには-jオプションを使い、マージしたいタグを指定します。ブランチタグの場合にはブランチの最新状態がマージされます【図7.2.22】。

【図7.2.22】トランクへブランチをマージする
▼
[トランク]% cvs update -j TESTBRANCH-1
cvs update: Updating .
RCS file: /home/cvsroot/branchtest/b1.txt,v
retrieving revision 1.3
retrieving revision 1.3.2.1
Merging differences between 1.3 and 1.3.2.1 into b1.txt
rcsmerge: warning: conflicts during merge
▲

【図7.2.22 6行目】に「1.3と1.3.2.1をマージしてb1.txtにしました」という意味のメッセージが表示されています。次の【図7.2.22 7行目】に警告(warning)が出ていることに注意してください。

ここで、statusコマンドでb1.txtの現在の様子を眺めてみます【図7.2.23】。

【図7.2.23】b1.txtの状態はどうなったかな?
▼
[トランク]% cvs status b1.txt
===================================================================
File: b1.txt            Status: File had conflicts on merge

   Working revision:    1.4     Result of merge
   Repository revision: 1.4     /home/cvsroot/branchtest/b1.txt,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)

▲

と、Statusの箇所にマージのときのコンフリクトがある(File had conflicts on merge)というメッセージがある【図7.2.23 3行目】ということと、Working revision:のところにマージの結果である【図7.2.23 5行目】ということが書かれています。

マージされた結果のb1.txtは【図7.2.24】のように、リビジョン1.4と1.3.2.1の間のコンフリクトを含みます。

【図7.2.24】コンフリクトが発生している状態のb1.txt
▼
This is a branch test file No.1 b1.txt.
Second commit.
<<<<<<< b1.txt
Conflict test.
=======
Branch first commit.
>>>>>>> 1.3.2.1
▲

【図7.2.24 3行目】の「<<<<<<< b1.txt」と【7行目】の「>>>>>>> 1.3.2.1」に囲まれた領域がコンフリクトを示しています。途中「=======」に区切られて、上と下にコンフリクトしたそれぞれの内容が書かれています。

開発者はこのような競合を眺めながら修正します。ここでは簡単に両方を足したような文に書き換えてしまいます【図7.2.25】。

【図7.2.25】修正されたb1.txt
This is a branch test file No.1 b1.txt.
Second commit.
Conflict test and branch first commit.
▲

そして、このb1.txtを安定したバージョンとしてコミットします【図7.2.26】。

【図7.2.26】修正されたb1.txtを「安定バージョン」としてコミットする
▼
[トランク]% cvs commit -m "Stable version of b1.txt" b1.txt
Checking in b1.txt;
/home/cvsroot/branchtest/b1.txt,v  <--  b1.txt
new revision: 1.5; previous revision: 1.4
done
▲

さらに、マージされた状態であることを示すために全体にタグ付けしておきます【図7.2.27】。

【図7.2.27】「安定バージョン」にタグ付け
▼
[トランク]% cvs tag merged-TESTBRANCH-1
cvs tag: Tagging .
T b1.txt
T b2.txt
T b3.txt
▲

これまでの作業過程と、各ファイルの変化を図で表すと【図7.2.28】のようになります。

【図7.2.28】トランクへのマージまでの作業の様子
f

一方、ブランチ側はトランク側でなされた変更を自分の方へ取り込む必要があります。マージ後、トランク側に変更がなければ、マージ時点のタグmerged-TESTBRANCH-1を使用しても構いませんが、トランク側で何か変更があった場合には、先頭を意味するHEADという特別なタグを使用します。また、ブランチ側は、さっきつけたばかりのタグTESTBRANCH-2を使用します。このタグは今のところ変更が少ないのであまり意味はないのですが…なんだかややこしいですね。

これを実行してみたのが【図7.2.29】です。

【図7.2.29】ブランチへトランクをマージする
▼
[ブランチ]% cvs update -j TESTBRANCH-2 -j HEAD
cvs update: Updating .
RCS file: /home/cvsroot/branchtest/b1.txt,v
retrieving revision 1.3.2.1
retrieving revision 1.5
Merging differences between 1.3.2.1 and 1.5 into b1.txt
▲

【図7.2.29 4-5行目】の出力を見る限りでは、ブランチ側の最新リビジョン1.3.2.1とトランク側の最新リビジョン1.5がマージされて新しいファイルになっているようです。結果はどうなったでしょうか。b1.txtについてdiffをとってみましょう【図7.2.30】。

【図7.2.30】ブランチのファイルの状況
▼
[ブランチ]% cvs diff -c b1.txt
Index: b1.txt
===================================================================
RCS file: /home/cvsroot/branchtest/b1.txt,v
retrieving revision 1.3.2.1
diff -c -r1.3.2.1 b1.txt
*** b1.txt      5 Sep 2002 14:37:25 -0000       1.3.2.1
--- b1.txt      5 Sep 2002 14:53:18 -0000
***************
*** 1,3 ****
  This is a branch test file No.1 b1.txt.
  Second commit.
! Branch first commit.
--- 1,3 ----
  This is a branch test file No.1 b1.txt.
  Second commit.
! Conflict test and branch first commit.
▲

最後にこれをコミットして、何か適当なタグをつけておけば他の人が使えて幸せになれます【図7.2.31】。

【図7.2.31】トランクをマージした状態をコミットしてタグをつける
▼
[ブランチ]% cvs commit -m "Merged from trunk: b1.txt" b1.txt
Checking in b1.txt;
/home/cvsroot/branchtest/b1.txt,v  <--  b1.txt
new revision: 1.3.2.2; previous revision: 1.3.2.1
done
[ブランチ]% cvs tag trunk-merged-TESTBRABCH-2
cvs tag: Tagging .
T b1.txt
T b2.txt
T b3.txt
▲

これまでの作業過程と各ファイルの変化を図示すると、【図7.2.32】のようになります。

【図7.2.32】ブランチへのマージまでの作業の様子

以上、ごく簡単なブランチの使い方を説明してみましたが、それでも頭がごちゃごちゃしてしまったかもしれませんね。筆者はブランチを使っていると良く頭が混乱します。タグを指定し間違えたりして、違うリビジョンをマージしてしまうこともあります。このように困った状態になってしまったら、一旦マージされてできたファイルを削除し、updateコマンドで最新版を取得後、改めてマージするようにするとよいでしょう。みなさんもいろいろと試行錯誤してみてください。

■■■ 7.2.6 WinCvsでブランチを扱おう

同じことをWinCvsでやってみましょう。まず、上で使用したものと同じbranchtestモジュールを作成して、コミットしておきます。リビジョンも合わせておいてください。【図7.2.33】のような感じになっていればOKです。

【図7.2.33】 b1.txtが1.3で、b2.txtは1.2、b3.txtは1.4になってるとしよう

また、実際にブランチの作成をするまえに、root-of-TESTBRANCH-1のタグをつけておきます。タグのつけ方は覚えてますか?忘れたという方は、4.1節を見直してみてください。ダイアログ【図7.2.34】のようにしてタグをつけておいてください。

【図7.2.34】 root-of-TESTBRANCH-1のタグをつけておこう

■■■■ブランチ作成

ブランチの作成には、メニュー[修正]→[分岐の作成(B)…]【図7.2.35】、あるいはタグバーからブランチアイコンを選んでtagコマンドを実行する方法と、メニュー[作成]→[モジュールに分岐を作成…]【図7.2.36】を選んでrtagコマンドを実行する方法の2つがあります。

【図7.2.35】 [修正]→[分岐の作成(B)…]メニュー

【図7.2.36】 [作成]→[モジュールに分岐を作成…]メニュー

ここでは、tagコマンドを使用した分岐の作成のみを紹介します。 tagコマンドを利用するメニューまたはアイコンを選択すると、【図7.2.37】のようなダイアログが現われます。

【図7.2.37】 分岐のための設定をしよう

ここで、ブランチのタグTESTBRANCH-1を「枝の名前(N)」という場所に入力して「OK」ボタンを押します。すると、アウトプット領域に【図7.2.38】のような出力があり、tagコマンドによりブランチが作成されたことがわかります。

【図7.2.38】tagコマンドの実行を確認
▼
cvs tag -b TESTBRANCH-1 (ディレクトリ C:\home\mika\workcopy\branchtest\ 内)
cvs tag: Tagging .
T b1.txt
T b2.txt
T b3.txt

*****CVS はコード 0 で終了しました*****
▲

■■■■ブランチ取り出し

WinCvsでブランチを取り出すときは、通常のチェックアウトの途中出てくるダイアログで、[オプション]タブを選びます。【図7.2.39】のように「特定のリビジョン・タグ・枝(R)」というところに取り出したいブランチのタグ(ここではTESTBRANCH-1)を入力する(か選択するか)します。

【図7.2.39】 チェックアウトダイアログのオプションを利用

ここでは作業の都合上、モジュール名とは別の名前(branchtest2)で取り出してます【図7.2.40】が、別にこれは必須ではありません。

【図7.2.40】 都合により別の名前

何にしろ、この状態で「OK」を押せば、【図7.2.41】のようなメッセージがアウトプット領域に出力され、ブランチのタグを指定してチェックアウトがおこなわれている様子がわかります。

【図7.2.41】tagコマンドの実行を確認
▼
cvs checkout -P -r TESTBRANCH-1 -d branchtest2 branchtest (ディレクトリ C:\home\mika\workcopy 内)
cvs checkout: Updating branchtest2
U branchtest2/b1.txt
U branchtest2/b2.txt
U branchtest2/b3.txt

*****CVS はコード 0 で終了しました*****
▲

そして、取り出された作業コピーを眺めてみると、タグのところにブランチのタグがついていることがわかります。

【図7.2.42】 おお、タグがついてる

■■■■ブランチのグラフ表示

WinCvsでなんといっても楽しいのは、このように複雑になってきたタグの様子をグラフ表示してみることです。グラフ表示の仕方自体は、4.1節で説明しましたので、ここではやりません。早速、b1.txtについて、現在のタグの状態を見てみましょう【図7.2.43】。

【図7.2.43】 タグのグラフ表示は楽しい

リビジョン1.3にroot-of-TESTBRANCH-1とTESTBRANCH-1の2つがついていることが見て取れます。

■■■■マージ

さらに、コマンドラインでやった作業を、ここでも繰り返して【図7.2.44】の状態までもっていきます。

【図7.2.44】

つまり、ブランチ側で編集→コミット(リビジョン1.3.2.1)→TESTBRANCH-2のタグ付け、トランク側で編集→コミット(リビジョン1.4)という作業をした状態とします。ここで、トランク側にブランチ側の変更をマージします。マージするには更新を利用します。更新の途中で現われるダイアログで[マージ]タブを選んでください【図7.2.45】。

【図7.2.45】 [マージ]タブの出番!

ここでは、トランク側でトランクとブランチの最新状態をマージするので、対象となるブランチのタグ(TESTBRANCH-1)だけを指定しています。「OK」を押して実行すると、【図7.2.46】のような出力が得られ、望んだマージが行われたことが確認できます。

【図7.2.46】
▼ cvs update -P -jTESTBRANCH-1 (ディレクトリ C:\home\mika\workcopy\branchtest\ 内) cvs update: Updating . RCS file: C:\home\cvsroot/branchtest/b1.txt,v retrieving revision 1.3 retrieving revision 1.3.2.1 Merging differences between 1.3 and 1.3.2.1 into b1.txt rcsmerge: warning: conflicts during merge *****CVS はコード 0 で終了しました***** ▲

ここで、トランク側の作業コピーの状態を眺めてみると、【図7.2.47】のようになっています。

【図7.2.47】 マージの残骸が…

マージによって、b1.txtがコンフリクトを起こしており、その影響で残骸(.#b1.txt.1.4)ができています。b1.txtについてはコンフリクトを解消する必要があります。残骸は放っておいても良いですが、気になるなら削除してください。b1.txtについてはコマンドラインでやった処置を施して、コミットします。test1.txtはりビジョンが1.5に上がります。コミット後、これにタグ(merged-TESTBRANCH-1)をつけます【図7.2.48】。

【図7.2.48】 マージ後のタグ付け

【図7.2.49】がこの状態でのタグの様子です。マージされたコミットされたリビジョン1.5にタグmerged-TESTBRANCH-1がついています。

【図7.2.49】 トランク側へのマージ後の状態

今度はブランチ側でのマージです。ブランチ側の最新状態とトランク側の最新状態をマージします。やはり更新を使用しますが、[マージ]タブでの指定が少し違います。今度は、「二つのリビジョン・タグの違いとマージ(P)」という場所にチェックを入れ、「特定のリビジョン・タグとマージ(O)」の入力場所も利用して、2つのタグを指定します。要は2つの-jオプションへ渡す引数を指定しているだけです。

2つのタグTESTBRANCH-2とHEADを【図7.2.50】のように指定します。

【図7.2.50】 TESTBRANCH-2とHEADを指定

そして、「OK」を押すと、例によって【図7.2.51】のような出力が得られます。

【図7.2.51】
▼ cvs update -P -jTESTBRANCH-2 -jHEAD (ディレクトリ C:\home\mika\workcopy\branchtest2\ 内) cvs update: Updating . RCS file: C:\home\cvsroot/branchtest/b1.txt,v retrieving revision 1.3.2.1 retrieving revision 1.5 Merging differences between 1.3.2.1 and 1.5 into b1.txt *****CVS はコード 0 で終了しました***** ▲

ブランチ側作業コピー(branchtest2)はどうなったでしょうか。トランク側へのマージと同様、コンフリクトによる変化が起きています【図7.2.52】。

【図7.2.52】 マージによるコンフリクトが…

このコンフリクトを例によって解消し、コミットします。リビジョンは1.3.2.2に上がります。そして、このリビジョンにマージ後のタグtrunk-merged-TESTBRANCH-2をつけます【図7.2.53】。

【図7.2.53】 マージ後のタグ付け

ここで、現状をグラフ表示してみると、【図7.2.54】のようになります。確かに、1.3.2.2の方にタグtrunk-merged-TESTBRANCH-2がついてますね。

試してみられた方は、お疲れ様でした。そうさ自体は、コマンドラインと大して変わりませんが、こんな風にグラフ表示できるのは助かりますね。