[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5. 枝とマージ

CVS では変更を (branch) として知られる別の開発ラインに 分けることができます。枝のファイルを変更しても、その変更は幹や他の枝に は現れません。

後程、マージ (merging) によって変更をある枝から別の枝 (も しくは幹) に移動することができます。マージはまず cvs update -j を実行して、変更を作業ディレクトリに混ぜることから始まります。それから そのリビジョンを格納することができ、こうして効果的に変更を別の枝にコピー することができます。

5.1 枝は何の役に立つか  
5.2 枝の作成  
5.3 枝のアクセス  枝の更新と取り出し
5.4 枝とリビジョン  枝はリビジョン番号に反映される
5.5 魔法の枝番号  
5.6 枝全体をマージする  
5.7 枝から何度もマージする  
5.8 二つのリビジョン間の差分をマージする  
5.9 ファイルの追加や削除もマージできる  ファイルが追加/削除された場合はどうか?
5.10 マージとキーワード  キーワード置換による衝突を回避する


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1 枝は何の役に立つか

tc のリリース 1.0 ができたとしましょう。tc の開発を継続していて、数ヶ 月の間にリリース 1.1 を作成する計画を立てています。しばらくして、顧客 が致命的なバグについて文句を言ってくるようになりました。リリース 1.0を 取り出し (see section 4.4 タグ--文字によるリビジョン)、バグを見つけました (結局些細な修正に終わりま した)。しかし、ソースの現在のリビジョンは流動的で、少くとも1ヶ月は安定 しない状態です。最新のソースに基づくバグ修正リリースはとても作成できま せん。

この様な状況でするべきことは tc のリリース 1.0 の全てのファイルのリビ ジョンツリーに基づく (branch) を作成することです。そう すれば幹の邪魔をすることなく枝に修正を加えることができます。修正が終わっ たときに、幹に取り込むか、枝に残しておくかを選択することができます。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2 枝の作成

tag -b で枝を作成することができます。例えば、作業コピーのところ にいるとしましょう:

 
$ cvs tag -b rel-1-0-patches

これは作業コピーの現在のリビジョンに基づいた枝を別に作成し、その枝に名 前 `rel-1-0-patches' を割当てます。

枝はリポジトリに作成されているのであって、作業コピーに作成されているの ではないということを理解することは重要です。上記の例の様に、現在のリビ ジョンに基づいた枝を作成することは、自動的に作業コピーを新しい枝に切り 換えることは しません。それをする方法に関する情報は 5.3 枝のアクセス を参照してください。

rtag を使って、作業コピーへの参照無しに枝を作ることもできます:

 
$ cvs rtag -b -r rel-1-0 rel-1-0-patches tc

`-r rel-1-0' はこの枝がタグ `rel-1-0' に対応するリビジョンを 根とするということを指定します。最新のリビジョンである必要はありません -- 古いリビジョンから枝を生やすことが役に立つことがしばしばあります (例えば、他の部分は安定していることが知られている過去のリリースのバグ を修正するとき)。

`tag' と同様に `-b' フラグは rtag に枝を作成するよう に指示します (単なるリビジョン名ではなく)。`rel-1-0' に対応する数 字リビジョン番号はファイル毎に違うことを注意してください。

ですから、命令の完全な効果は新しい枝を作成することです -- モジュール `tc' で、`rel-1-0' でタグ付けされたリビジョンツリーを根元と する -- `rel-1-0-patches' という名前のものを。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3 枝のアクセス

2 つの方法のどちらかで枝を取得することができます: リポジトリから新しく 取り出すか、存在する作業コピーをその枝に切り換える方法です。

リポジトリから枝を取り出すには `checkout' をフラグ `-r' と、 その後に枝のタグ名を続けて起動します (see section 5.2 枝の作成)。

 
$ cvs checkout -r rel-1-0-patches tc

もしくは、既に作業コピーを持っていれば、`update -r' で任意の枝に 切り換えることができます:

 
$ cvs update -r rel-1-0-patches tc

もしくは、それと等価な:

 
$ cd tc
$ cvs update -r rel-1-0-patches

作業コピーが元々幹にあったか他の枝にあったかは関係ありません -- 上のコ マンドはそれを指定された名前の枝に切り換えます。普通の `update' コマンドと同様に、`update -r' は全ての変更をマージし、衝突がどこ で起こったかを知らせます。

一度特定の枝に結び付けられた作業コピーを手に入れると、指示しない限りそ こに残り続けます。これは、作業コピーから格納された変更はその枝に新しい リビジョンを加えますが、幹と他の枝には影響を及ぼさないということです。

作業コピーがどの枝であるかを知るために、コマンド `status' を使う ことができます。その出力で、`Sticky tag' という名前の場所を探して ください (see section 4.9 貼り付いたタグ) -- それは現在の作業ファイルに、もし枝が あれば、それを教える CVS の方法です:

 
$ cvs status -v driver.c backend.c
===================================================================
File: driver.c          Status: Up-to-date

    Version:            1.7     Sat Dec  5 18:25:54 1992
    RCS Version:        1.7     /u/cvsroot/yoyodyne/tc/driver.c,v
    Sticky Tag:         rel-1-0-patches (branch: 1.7.2)
    Sticky Date:        (none)
    Sticky Options:     (none)

    Existing Tags:
        rel-1-0-patches             (branch: 1.7.2)
        rel-1-0                     (revision: 1.7)

===================================================================
File: backend.c         Status: Up-to-date

    Version:            1.4     Tue Dec  1 14:39:01 1992
    RCS Version:        1.4     /u/cvsroot/yoyodyne/tc/backend.c,v
    Sticky Tag:         rel-1-0-patches (branch: 1.4.2)
    Sticky Date:        (none)
    Sticky Options:     (none)

    Existing Tags:
        rel-1-0-patches             (branch: 1.4.2)
        rel-1-0                     (revision: 1.4)
        rel-0-4                     (revision: 1.4)

それぞれのファイルの枝番号が違うという事実に混乱しないでください (それぞれ `1.7.1' と `1.4.2' です)。枝タグは同じ `rel-1-0-patches' で、ファイルは実際に同じ枝にあります。番号は単 に枝が作られたときのそれぞれのファイルのリビジョン履歴を反映しています。 上の例では、この枝が作成される前に、`driver.c' が `backend.c' よりも多くの変更が成されたということを導き出すことが できます。

枝番号が作成される方法の詳細は 5.4 枝とリビジョン を参照して ください。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4 枝とリビジョン

普通はファイルのリビジョン履歴は線形増加です (see section 4.1 リビジョン番号):

 
       +-----+    +-----+    +-----+    +-----+    +-----+
       ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
       +-----+    +-----+    +-----+    +-----+    +-----+

しかし、CVS は線形の開発に限られているわけではありません。リ ビジョン・ツリー に分割することができ、それぞれの枝は別に 維持された開発ラインです。枝になされた変更は簡単に幹に戻すことができま す。

それぞれの枝には 枝番号 があり、ピリオドで分けられた奇数個の10進 整数から成ります。枝番号は枝が分岐した元の枝に対応するリビジョン番号に 整数を追加することによって作成されます。枝番号により、特定のリビジョン から 1 つ以上の枝を枝分かれすることができます。

枝の全てのリビジョンは枝番号に普通の数字を追加することで形成されます。 下図に、前述の例から枝が発展した例を示します。

 
                                                      +-------------+
                           Branch 1.2.2.3.2 ->        ! 1.2.2.3.2.1 !
                                                    / +-------------+
                                                   /
                                                  /
                 +---------+    +---------+    +---------+
Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
               / +---------+    +---------+    +---------+
              /
             /
+-----+    +-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !  <- The main trunk
+-----+    +-----+    +-----+    +-----+    +-----+
                !
                !
                !   +---------+    +---------+    +---------+
Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 !
                    +---------+    +---------+    +---------+

枝番号が作成される厳密な詳細は普通は気にしなくて良いのですが、以下が動 作の方法です: CVS が枝番号を作成するときは、2 から始まる最初の未 使用の偶数を選びます。ですから、リビジョン 6.4 から枝を作成したいとき は、それは 6.4.2 という番号になるでしょう。零で終わる全ての枝番号 (6.4.0 のように) は CVS の内部で使用されます (see section 5.5 魔法の枝番号)。枝 1.1.1 は特別な意味を持ちます。See section 13. サード・パーティーのソースの追っかけ.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.5 魔法の枝番号

この部分は 魔法の枝 (magic brandh) と呼ばれる CVS の 機能を説明します。たいていの目的のためには魔法の枝を心配する必要はあり ません。CVS が代わりに扱ってくれます。しかし、特定の状況ではそれ が見えていることもありますので、いくらか動作の仕方を知っていると役に立 つかもしれません。

表面的には、枝番号はドットで分けられた奇数個の10進の整数です。 See section 4.1 リビジョン番号. しかし、これは真実の姿ではありません。 CVS は能率のために、余分な 0 を右から2番目の位置に挿入することが あります(1.2.3 は 1.2.0.3 となり、8.9.10.11.12 は 8.9.10.11.0.12 にな ります)。

この魔法の枝と呼ばれるものを、CVS はうまく隠しています。しかし、 完璧に隠し切れていないところも数ヶ所あります。

admin コマンドを使用して、 RCS が枝のタグ名を理解できるように再設定する方法があります。 R4patches というタグ名が、 ファイル `number.c' の枝 1.4.2 に付けられている場合 (魔法の枝番号は 1.4.0.2 です)、 次のようにします:

 
$ cvs admin -NR4patches:1.4.2 numbers.c

この方法を用いる場合は、1つ以上のリビジョンが、 既に枝に格納されている必要があります。 タグに間違った番号を設定しないように、注意しなくてはいけません。 (実行以前にタグがどう設定されていたかを調べる方法はありません)。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.6 枝全体をマージする

update サブコマンドに `-j branchname' フラグを付けると、 枝に加えられた変更を作業コピーに反映することができます。 `-j branchname' オプションが一つだけだと、 枝と目的リビジョンの最大共通祖先 (greatest common ancestor, GCA) (下の簡単なれいでは GCA は 枝の分岐点と枝の最新リビジョン間の違い) を (あなたの作業コピーに) マージします。

`-j' は、"join" の略です。

次のリビジョン・ツリーを考えます。

 
+-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !      <- The main trunk
+-----+    +-----+    +-----+    +-----+
                !
                !
                !   +---------+    +---------+
Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
                    +---------+    +---------+

枝 1.2.2 には `R1fix' というタグ (文字列) が付けられています。次 は `m.c' というファイル1つを含むモジュール `mod' の例です。

 
$ cvs checkout mod               # 最新のリビジョン 1.4 を取り出す

$ cvs update -j R1fix m.c        # 枝で行なわれた変更(リビジョン 1.2
                                 # と 1.2.2.2 の差分)を作業コピーに追加

$ cvs commit -m "Included R1fix" # リビジョン 1.5 を作成

マージ作業で衝突が起きることもありますが、衝突が起きた場合は、それを解 決してから新しいリビジョンを格納して下さい。 See section 10.3 衝突の例.

もしソースファイルにキーワードがあれば (see section 12. キーワード置換), 本当に必要なものよりも余分に衝突を得るかもしれません。これを回避する方 法は 5.10 マージとキーワード を参照してください。

checkout コマンドでもフラグ `-j branchname' を使用できます。 以下の様にして上記と同じ効果を得ることができます:

 
$ cvs checkout -j R1fix mod
$ cvs commit -m "Included R1fix"

update -j tagname も動作しますが、おそらく望んだ結果をもたらさない であろうことに注意してください。詳細は See section 5.9 ファイルの追加や削除もマージできる.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.7 枝から何度もマージする

前節の例を続けると、 現在のリビジョン・ツリーは次の様になっています:

 
+-----+    +-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !   <- The main trunk
+-----+    +-----+    +-----+    +-----+    +-----+
                !                           *
                !                          *
                !   +---------+    +---------+
Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
                    +---------+    +---------+

前節で枝 `R1fix' を幹にマージした事を、ここでは星線で表します。

次に、枝 `R1fix' で開発が続けられたと仮定します:

 
+-----+    +-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !   <- The main trunk
+-----+    +-----+    +-----+    +-----+    +-----+
                !                           *
                !                          *
                !   +---------+    +---------+    +---------+
Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
                    +---------+    +---------+    +---------+

そしてこの新しい変更を幹にマージしたくなりました。 ここで再び cvs update -j R1fix m.c コマンドを用いた場合、 CVS は既にマージされた変更点を重ねてマージしようとして、 望ましくない結果をもたらします。

そこで、 未だ幹にマージされてない変更点だけマージしたい旨を、 明示する必要があります。 これには、`-j' オプションで二つのリビジョンを指定します。 CVS は、 最初のリビジョンから次のリビジョンまでの変更をマージします。 例えば、この場合、最も簡単な方法は次の様になります。

 
cvs update -j 1.2.2.2 -j R1fix m.c    # 1.2.2.2 から、枝 R1fix の
                                      # 先頭までの変更をマージする

この方法の問題点は、リビジョン 1.2.2.2 を自分で指定する必要がある事です。 最後にマージが行われた日時を使用する方が、少しましでしょう:

 
cvs update -j R1fix:yesterday -j R1fix m.c

さらに良いのは、 変更点を幹にマージする度に、 枝 `R1fix' にタグを振っておき、 後でマージする時にそのタグを用いる方法です:

 
cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.8 二つのリビジョン間の差分をマージする

update (と checkout) コマンドに `-j revision' フラグを二つ付けることで、任意の二つのリビジョン間の違いをあなたの作業 コピーに加えることができます。

 
$ cvs update -j 1.5 -j 1.3 backend.c

このようにするとリビジョン 1.3 と 1.5 間の変更を 全て元に戻すことになります。 リビジョンを指定する順序に十分注意して下さい!

複数のファイルに対してこのオプションを指定する場合は、 ファイルごとにリビジョン番号が全く異なるであろうことを思い出して下さい。 複数のファイルを操作する場合には、 リビジョン番号ではなく、 必ずタグ名を用いるようにして下さい。

2つ `-j' オプションを指定すると、追加や削除を元に戻すこともできま す。例えば、リビジョン1.1として存在していた `file1' という名前の ファイルがあり、それを消去した (つまり、死んだリビジョン1.2を追加しま した) としましょう。今、またそれを以前と同じ内容で追加したいと思ったと しましょう。これがそれをする方法です:

 
$ cvs update -j 1.2 -j 1.1 file1
U file1
$ cvs commit -m test
Checking in file1;
/tmp/cvs-sanity/cvsroot/first-dir/file1,v  <--  file1
new revision: 1.3; previous revision: 1.2
done
$


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.9 ファイルの追加や削除もマージできる

マージする変更点に、ファイルの削除や追加が伴なう場合でも、 update -j は削除や追加を反映します。

実行例:

 
cvs update -A
touch a b c
cvs add a b c ; cvs ci -m "added" a b c
cvs tag -b branchtag
cvs update -r branchtag
touch d ; cvs add d
rm a ; cvs rm a
cvs ci -m "added d, removed a"
cvs update -A
cvs update -jbranchtag

これらのコマンドが実行され、`cvs commit' がなされた後、幹ではファ イル `a' は削除され、ファイル`d' は追加されます

枝からのマージの変更に動的なタグ (`-j branchname') の代わりに 静的なタグ (`-j tagname') が使われたときは枝で削除された ファイルは削除されません。CVS は死んだリビジョンには自動的に 静的なタグを追加しないからです。この規則の例外は、手動で死んだリビジョンに タグが追加されたときです。枝からのすべての変更をマージするために枝タグを 使うか、マージの両端に静的なタグを指定して、意図した変更すべてが マージに含まれるようにしてください。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.10 マージとキーワード

キーワードを含むファイルをマージすると (see section 12. キーワード置換、 通常マージの間に数多くの衝突が起こります。なぜなら、キーワードはマージ 中のリビジョンで違う様に展開されているからです。

ですから、しばしばマージのコマンド行で `-kk' (see section 12.4 置換モード) スイッチを指定したいと思うでしょう。キーワードの展開された値を 展開するのでは無く、キーワードの名前だけを置換することによって、このオ プションはマージしているリビジョンがそれぞれ同じことを確実にして、見せ かけの衝突を回避します。

例えば、このようなファイルがあるとしましょう:

 
       +---------+
      _! 1.1.2.1 !   <-  br1
     / +---------+
    /
   /
+-----+    +-----+
! 1.1 !----! 1.2 !
+-----+    +-----+

そして、作業ディレクトリは現在幹 (revision 1.2) にあります。そうすると、 以下の結果をマージから得るでしょう:

 
$ cat file1
key $Revision: 1.2 $
. . .
$ cvs update -j br1
U file1
RCS file: /cvsroot/first-dir/file1,v
retrieving revision 1.1
retrieving revision 1.1.2.1
Merging differences between 1.1 and 1.1.2.1 into file1
rcsmerge: warning: conflicts during merge
$ cat file1
<<<<<<< file1
key $Revision: 1.2 $
=======
key $Revision: 1.1.2.1 $
>>>>>>> 1.1.2.1
. . .

これで起こったことは、merge が 1.1 と 1.1.2.1 間の差分を作業ディレクト リにマージしようとした、ということです。キーワードはRevision: 1.1 から Revision: 1.1.2.1 へと変わっているので、CVS はそ の変更を作業ディレクトリにマージしようとして、それは作業ディレクトリが Revision: 1.2 を含んでいた、という事実と衝突をしました。

これは `-kk' を使用したときにに起こることです:

 
$ cat file1
key $Revision: 1.9 $
. . .
$ cvs update -kk -j br1
U file1
RCS file: /cvsroot/first-dir/file1,v
retrieving revision 1.1
retrieving revision 1.1.2.1
Merging differences between 1.1 and 1.1.2.1 into file1
$ cat file1
key $Revision$
. . .

ここでは、リビジョン 1.1 とリビジョン 1.1.2.1 の両方ともが Revision に展開され、それらの変更を作業コピーにマージすることは 何も変更しません。ですから、衝突は起こりません。

しかしながら、マージで `-kk' を使うことには一つ大きな注意がありま す。つまり、それは普通は CVS が使っていたであろうキーワード展開の 様式を上書きします。特に、これは、バイナリファイルのために様式が `-kb' であったときに問題になります。ですので、リポジトリにバイナ リファイルがあるときは、`-kk' を使用するよりは、衝突に対処する必 要があるでしょう。


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Yoshiki Hayashi on October, 13 2004 using texi2html