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

10. 複数の開発者

複数の人間でソフトウェア開発を行なうと、色々面倒が起こります。 例えば二人の人物が、 同じファイルを同時に編集しようとすることがよくあります。 解決策の一つは、 ファイル占有 (file locking) または 独占取得 (reserved checkouts) と呼ばれるもので、 同時にファイルを編集できる人数を一人に制限するものです。 RCSSCCS 等の履歴管理システムでは、 これが唯一の方法です。 現時点では CVS で独占取得をする普通の方法は cvs admin -l コマンドです (see section admin のオプション)。これは後述する監視機能のように CVS によく実装されてはいませんが、独占取得を必要なほとんどの人は 十分だと思うでしょう。 また後述する監視機構を適切な手順を踏んで用いることでも (ソフトウェアか らは強制されません)、同時編集を避けることが可能でしょう。

CVS の既定モデルは無条件取得 (unreserved checkouts) と呼ばれるものです。 このモデルでは、 開発者がそれぞれ自分の 作業コピー (working copy) のファイルを同時に編集できます。 最初に変更を格納した人物は、 他の人物が編集を始めたことが自動的には分りません。 二番目の人物が格納する時にはエラー表示を受けますから、 CVS コマンドを用いて、 自分の作業コピーをリポジトリのリビジョンの最新のものにする 必要があります。 この手順はほぼ自動化されています。

CVS は、独占取得がするような規則を強制することなく、 種々の意志疎通を容易にする仕組みを用意しています。

この章の残りでは、色々なモデルの動作方法と、 各モデルの選択に伴なう問題点について述べます。


10.1 ファイル状態

取り出した後にあなたが加えた操作や、 他の人物がリポジトリに加えた操作によって、 ファイルを幾つかの状態に分類します。 status コマンドによって報告される状態を以下に挙げます:

Up-to-date

このファイルが、 使用している枝の最新リビジョンと同じであることを示します。

Locally Modified

このファイルを修正したが、まだ変更内容を格納してないことを示します。

Locally Added

add コマンドによりファイルを加えたが、 まだその内容を格納してないことを示します。

Locally Removed

remove コマンドによりファイルを削除したが、 まだその変更を格納してないことを示します。

Needs Checkout

他の人物が新しいリビジョンをリポジトリに格納したことを示します。 この表示は少し紛らわしいのですが、 新しいリビジョンを取り出す際には、checkout ではなく、 update を使用するのが普通です。

Needs Patch

Needs Checkout と似たようなものですが、 CVS のサーバは、ファイル全てではなく差分を送ります。 差分を送る場合も、ファイル全てを送る場合と結果は同じです。

Needs Merge

他の人物が新しいリビジョンをリポジトリに格納したが、 作業ファイルも修正されていたため、マージする必要があることを示します。

File had conflicts on merge

Locally Modified と似ていますが、先の update コマンドの結果、 変更点の衝突が発見されたことを示します。 衝突を解消する方法は 衝突の例 参照。

Unknown

このファイルについて CVS が何も知らないことを示します。 例えば新たなファイルを作成したが、add を実行していない場合などです。

status は、ファイル状態を分類する際の補助として、 作業中のファイルの由来となるリビジョン を示す `Working revision' と、 使用中の枝のリポジトリにおける最新リビジョン を示す `Repository revision' とも報告します。

status コマンドのオプションについての情報は、CVS コマンドの簡単な便覧 参照。 `Sticky tag' と `Sticky date' についての 情報は、貼り付いたタグ 参照。 `Sticky options' の情報は、update のオプション の `-k' オプションを参照して下さい。

statusupdate コマンドは補完するようなものとして考え ることができます。ファイルを最新にするためには update を使い、 statusupdate が何をするかをある程度知ることができま す (もちろん、リポジトリの状態は実際に update を実行するまでに 変化するかもしれません)。実際は、status コマンドで表示されるよ り短い形式でコマンドに表示させたければ、次を実行することができます

 
$ cvs -n -q update

`-n' オプションは実際に update をしないが、状態を表示するだけであ る、ということです。`-q' オプションはそれぞれのディレクトリ名の印 字を避けます。update コマンドとこれらのオプションの情報は、 CVS コマンドの簡単な便覧 を参照してください。


10.2 ファイルを最新にする

ファイルを更新もしくはマージしたい場合には、 update コマンドを使用します。 これは最新でないファイルに対しては checkout コマンドとほとんど 等価です。 つまり、ファイルの最新リビジョンをリポジトリから取り出して、 作業ディレクトリに置きます。

update コマンドを使用しても、 あなたの修正が失なわれることはありません。 より新しいバージョンが無い場合には、update は何もしません。 新しいバージョンが存在し、かつ作業ファイルが修正されている場合、 CVS は全ての変更を作業コピーにマージします。

例えばリビジョン 1.4 を取り出して、編集を始めたとします。 その合間に他の人物がバージョン 1.5 を格納し、 またすぐに 1.6 になったとします。 ここで update コマンドを使用した場合、 CVS は 1.4 と 1.6 間の変更を、あなたのファイルに組み入れます。

1.4 と 1.6 間の変更が、あなたの変更と似たようなものであれば、 重複 (overlap) が起きます。 そして警告が表示され、ファイルには重複した行が両方並記されて、 特別なマークで囲まれます。 update コマンドの詳細は See section update--作業コピーをリポジトリと一致させる.


10.3 衝突の例

リビジョン 1.4 の `drive.c' は次のような内容とします:

 
#include <stdio.h>

void main()
{
    parse();
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
    exit(nerr == 0 ? 0 : 1);
}

リビジョン 1.6 では `drive.c' は次のようになっています:

 
#include <stdio.h>

int main(int argc,
         char **argv)
{
    parse();
    if (argc != 1)
    {
        fprintf(stderr, "tc: No args expected.\n");
        exit(1);
    }
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
    exit(!!nerr);
}

リビジョン 1.4 を元にしたあなたの `driver.c' の作業コピーは、 `cvs update' の前に次ようになっています:

 
#include <stdlib.h>
#include <stdio.h>

void main()
{
    init_scanner();
    parse();
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
    exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}

この時 `cvs update' を実行してみます:

 
$ cvs update driver.c
RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v
retrieving revision 1.4
retrieving revision 1.6
Merging differences between 1.4 and 1.6 into driver.c
rcsmerge warning: overlaps during merge
cvs update: conflicts found in driver.c
C driver.c

CVS は上記のように、衝突が起きたことが報告します。 あなたが編集したオリジナルのファイルは、 無修正で `.#driver.c.1.4' という名前で保存されます。 `driver.c' の新しいバージョンは次のようになります:

 
#include <stdlib.h>
#include <stdio.h>

int main(int argc,
         char **argv)
{
    init_scanner();
    parse();
    if (argc != 1)
    {
        fprintf(stderr, "tc: No args expected.\n");
        exit(1);
    }
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
<<<<<<< driver.c
    exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
=======
    exit(!!nerr);
>>>>>>> 1.6
}

重複しなかった修正がどの様に作業コピーに組み込まれているか注意して下さ い。 重複した部分は `<<<<<<<', `=======' 及び `>>>>>>>' ではっきりと囲まれています。

ファイルを編集して衝突が起きた部分を解決し、 マークと間違った行を消します。 最終的に次のようになったとします:

 
#include <stdlib.h>
#include <stdio.h>

int main(int argc,
         char **argv)
{
    init_scanner();
    parse();
    if (argc != 1)
    {
        fprintf(stderr, "tc: No args expected.\n");
        exit(1);
    }
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
    exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}

今やこのファイルを格納してリビジョン 1.7 とすることができます。

 
$ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c
Checking in driver.c;
/usr/local/cvsroot/yoyodyne/tc/driver.c,v  <--  driver.c
new revision: 1.7; previous revision: 1.6
done

衝突が起きたが未解決であるファイルは、安全を考慮して、 CVS が格納することを拒否します。 衝突を解決するとき、ファイルの編集時間を変更する必要があります。 前のバージョンの CVS では、ファイルに衝突マークがないことを確認す る必要もありました。ファイルには正しく衝突マークがあるかもしれませんの で (すなわち、行頭にある `>>>>>>> ' は衝突の印ではありません)、現 在のバージョンの CVS は警告を印字してファイルの格納を実行します。

もしあなたが pcl-cvs (GNU Emacs 用 CVS フロントエンド) の、 1.04 よりも新しいリリースを使用しているならば、衝突を解決するのに emerge という Emacs パッケージが利用できます。 pcl-cvs の文書を見て下さい。


10.4 格納したことを他の人に知らせる

新しいリビジョンが格納されたときに、 それを開発者全員に通知するようにしておくと便利でしょう。 `modules' ファイルの `-i' オプションか `loginfo' ファイル により、この手順を自動化することができます See section The modules file. See section 管理用ファイル loginfo. この機構により、例えば全ての開発者にメールを出したり、 ニュースに記事を投稿したりすることができます。


10.5 同時に CVS の実行を試みる複数の開発者

複数の開発者が同時に CVS を実行しようとした場合、 次のようなメッセージが表示されます:

 
[11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo

CVS は 30秒毎に実行を試み、 まだ待つ必要があれば再度メッセージを表示し、 そうでなければ処理を続けます。 不適当な程長く待ち続けているようならば、 ロックさせている人物を見付けて、 実行中の cvs コマンドを訊いてみて下さい。 cvs コマンドが実行されてないのならば、メッセージで書かれているリポジト リディレクトリを見て、彼等が所有している `#cvs.tfl', `#cvs.rfl', `#cvs.wfl' という名前で始まるファイルを捜して、削除して下さい。

このロックは CVS の内部データ構造を保護するもので、 RCS で使用されるロック (lock) という言葉とは全く何の関係もないことに注意してください。 RCS のロックについては、 独占取得についての記述を参照して下さい (see section 複数の開発者)。

任意のリポジトリから何人でも、 同時に読み出すことが可能です。 誰かが書き込み中の場合にだけ、 他の人の読み出しや書き込みが禁止されます。

次に示すような動作を望む人がいるでしょう

 
ある人物が一つの cvs コマンドで複数のファイルに対する変更点を
格納した時、他の誰かが同時に update を実行すると、全てのファイルが
更新されるか、全く更新されないかのどちらかである。

が、CVS はこのように動作しません。 例えば以下のファイルがあるとして、

 
a/one.c
a/two.c
b/three.c
b/four.c

ある人物が次のコマンドを実行した時、

 
cvs ci a/two.c b/three.c

同時に他の誰かが cvs update を実行した場合、 update を実行している人は `b/three.c' の変更点のみが更新さ れ、 `a/two.c' の変更点は更新されないでしょう。


10.6 ファイル編集者の追跡機構

多くのグループが CVS を既定状態で使用していますが、 ほぼ完全に満足しているようです。 しかし時には、自分と他人の修正点が重複する事があり、 この重複を処理して再び格納しなくてはいけません。 あるグループでは、 誰がどのファイルを編集中か分るようにしています。 従って、二人で同じファイルを編集する場合、 誰が何時何をするのか相談できるため、 格納時に驚かされずに済みます。 この節では、 このような調整作業を行なう機能について説明しますが、 二人の開発者が同時に同じファイルを編集する能力は維持されます。

開発者は、 編集するファイルを読み書き可能にする時に、 (chmod でなく) cvs edit を使用し、 もう使用しない作業ディレクトリを処分する時に、 (rm でなく) cvs release を使用することが推奨されます。 しかし、CVS はこれらの手順を強制する事は出来ません。


10.6.1 監視するファイルを CVS に教える

監視機能を有効にするには、 まずそのファイルを監視するように指示する必要があります。

コマンド: cvs watch on [-lR] files …

この指定以降、files を編集しようとする開発者は cvs edit を実行する必要があります。 開発者が編集前に cvs edit の実行を忘れない様に、 CVSfiles の読み込みだけを許可します。

files がディレクトリを含む場合、 リポジトリの対応するディレクトリ内の全てのファイルに加えて、 将来ディレクトリに追加されるファイル全てが CVS の監視対象になります。 この動作を利用して、ディレクトリ毎に通知方針を設定することができます。 またオプション `-l' を指定しない場合、 ディレクトリ以下が再帰的に処理されます。 -l オプションが `~/.cvsrc' で設定されている場合は -R オプションを使って再帰を強制することができます (see section 既定オプションと ~/.cvsrc ファイル)。

files を省略した場合、 現在のディレクトリが指定されたと解釈します。

コマンド: cvs watch off [-lR] files …

取り出し時に files を読み込み専用にはしません。ですから、開発者 は cvs editcvs undit の使用に注意することはありませ ん。CVS は `config' 管理ファイルで PreservePermissions オ プションを使用すうことになっいるための他の使用許可の条件が無いかぎり、 files を 普通に読み書き両用で取り出します。(see section 特別なファイル, see section The CVSROOT/config configuration file).

files や引数指定時の振舞いは、 cvs watch on の場合と同じです。


10.6.2 誰に通知するか CVS に教える

あるファイルに対して種々の操作が行われた時に通知を受けたい場合には、 その旨を CVS に知らせます。 そのファイルに対して cvs watch on を用いなくても、 通知の要求は可能です。 しかし、開発者がコマンド cvs edit を用いるとは限らないため、 通常は cvs watch on を用いた方が良いでしょう。

コマンド: cvs watch add [-a action] [-lR] files …

現在の使用者を、 files に対して操作が行なわれた時に 通知を受けとる人の一覧に追加します。

オプション `-a' には、 通知して欲しい操作の種類を指定します。 action は次のうちのどれかです:

edit

あなた以外の人物が、 ファイルに対してコマンド cvs edit (後述) を適用した場合。

unedit

あなた以外の人物が、 ファイルに対してコマンド cvs unedit (後述) または cvs release を適用した場合。 また、ファイルが消されて cvs update により再度生成された場合。

commit

あなた以外の人物が、ファイルに対する変更を格納した場合。

all

上記全て。

none

上記以外。 (これは後述の cvs edit で使用すると便利です。)

オプション `-a' は何度指定しても良いし、 全く指定しなくても構いません。 省略した場合には、all が指定されたと解釈します。

files や引数指定時の振舞いは、 cvs watch on の場合と同じです。

コマンド: cvs watch remove [-a action] [-lR] files …

cvs watch add で設定した通知要求を取り下げます。 引数は同じです。 オプション `-a' を用いた場合、 指定された事項に対する通知のみを停止します。

通知すべき状態が発生した時、 CVS は管理用ファイル `notify' を見ます。 `notify' は他の管理用ファイルと同じように編集して下さい。 (see section 管理用ファイルの紹介)。 管理用ファイルの慣例に従って (see section 共通の構文)、このファイルの各行には、 正規表現に続けて実行したいコマンドを記述します。 コマンドの引数には、(通知すべき使用者に置換される) `%s' という文字列を一つだけ指定する必要があり、 通知内容はコマンドの標準入力に与えられます。 ファイル notify に書く標準のものは次の一行です:

 
ALL mail %s -s \"CVS notification\"

この記述により、使用者に電子メールで通知が行なわれます。

上記の行をそのまま記述した場合、 使用者はサーバ上で通知を受ける事に注意して下さい。 他の場所に通知したい場合には、 もちろん `notify' に記述しても良いのですが、 CVS ではもっと簡単に各使用者の通知先を設定できます。 `CVSROOT' に `users' というファイルを作成し、 user:value という書式で、 各使用者について一行ずつ記述して下さい。 CVS は、`notify' に記述された user の代りに、 value (通常は別のマシンのメールアドレス) に通知します。

CVS はあなた自身の変更は通知しません。現時点では、この照合は通知 を発生させる動作をしている人の使用者名が通知を受ける人の使用者名と合う かどうかに基づいてなされています。実際のところ、一般的に、監視機構はそ れぞれの使用者の一つの編集だけを追跡します。おそらく、監視がそれぞれの 作業ディレクトリを別に追跡するとより便利なので、この振舞いは変更する 価値があるでしょう。


10.6.3 監視下にあるファイルの編集方法

監視下にあるファイルを取り出した場合、 読み込みだけが許可されるため、単純に編集はできません。 読み書きを可能にし、そのファイルを編集する意図を他の人に伝えるために、 cvs edit コマンドを使用して下さい。 上記の作業を checkout と呼ぶシステムもありますが、 CVS ではこの用語をソースのコピーを得る (取り出す) という意味で用います (see section ソースの取得)。 他のシステムでは、この操作は get とか fetch と呼ばれます。

コマンド: cvs edit [options] files …

作業ファイル files を編集する準備をします。 CVSfiles の読み書きを許可し、 files に対する edit 通知を求める使用者に通知します。

cvs edit コマンドに、 cvs watch add コマンドと同じ options を使用すれば、 一時的に files を監視することができます。 CVS は、 filesunedit もしくは commit されたときに、 監視を止めます。 通知を受けたくない場合には、`-a none' を指定して下さい。

files や引数指定時の振舞いは、 cvs watch の場合と同じです。

注意: PreservePermissions オプションがリポジトリで使用 可になっていると (see section The CVSROOT/config configuration file)、CVS はどの files の使用許可も 変更しません。この変更の理由は `cvs edit' の使用が CVS リポジトリ のファイル使用許可を保管する機能と干渉しないようにするということです。

変更を全て終了したら、通常は cvs commit を用いて、 監視下にあるファイルの変更点を格納し、 読み込みだけが許可された状態に戻します。 しかし、途中で変更を止めたり、何も変更しないと決めた場合には、 cvs unedit コマンドを使用します。

コマンド: cvs unedit [-lR] files …

作業ファイル files に加えた変更を捨て、 変更前のリポジトリのバージョンに戻します。 files に対して、cvs watch on による通知要求がある場合、 CVSfiles の読み込みだけを許可します。 また files に対する unedit 通知を求める使用者に通知します。

files や引数指定時の振舞いは、 cvs watch の場合と同じです。

ファイルが監視されてないときにはおそらく unedit コマンドが動作しないため、 リポジトリのバージョンに戻したい場合は、ファイルを削除してから cvs update で新たにコピーを取得して下さい。 これは厳密には同じ意味ではなく、削除して更新した場合には、 あなたが最後に更新した後にリポジトリに加えられた変更も付随します。

CVS のクライアント/サーバを使用していて、 サーバとうまく接続できなかった場合でも、 cvs editcvs unedit コマンドが使用できます。 次に CVS コマンドが成功した時に、 一緒に通知が行なわれます。


10.6.4 誰が監視や編集をしているか

コマンド: cvs watchers [-lR] files …

現在、files の変更を監視している人物の一覧を表示します。 監視されているファイルと、各監視者のメールアドレスを報告します。

files や引数指定時の振舞いは、 cvs watch の場合と同じです。

コマンド: cvs editors [-lR] files …

現在、files を編集している人物の一覧を表示します。 各編集者のメールアドレス、編集作業を開始した時間、 ファイルが置かれた作業ディレクトリのパス名とホスト名を報告します。

files や引数指定時の振舞いは、 cvs watch の場合と同じです。


10.6.5 古いバージョンの CVS と監視機能

監視機能を使用している場合、 リポジトリに `CVS' というディレクトリが作成され、 このディレクトリに監視情報が格納されます。 このリポジトリに対して CVS 1.6 以前のものを使用した場合には、 以下のエラー・メッセージが出力されます (全て一行にでます):

 
cvs update: cannot open CVS/Entries for reading:
No such file or directory

そして、操作が途中で終了します。 監視機能を使用するためには、 このリポジトリを利用するクライアント/サーバ両方で、 CVS を新しいものと交換する必要があります。 もし新しいものと交換できない場合には、 watch offwatch remove コマンドを用いて 監視を全て停止すれば、 リポジトリを CVS 1.6 が利用できる状態に再構築できます。


10.7 独占取得と無条件取得の選択

独占取得、無条件取得それぞれに一長一短があります。 ここでは、この問題を簡単に説明しますが、 残りの多くは個人的な見解の相違や、 各グループの作業スタイルの相違だと思います。 開発者チームを構成するには様々な方法があります。 CVS は特定の構成を強制せず、 各々を実現する機能を提供するだけです。

独占取得には、非常に非生産的な部分があります。 二人が同じファイルを編集する場合でも、編集部分が異なる場合には、 どちらか一方の編集を禁止する必要は全くありません。 また、ファイルを編集するためにロックした後、 ロック解除を忘れてしまうことが、普通に起こり得ます。

独占取得に特別な安心感を持つ人々は、 無条件取得を用いた場合の衝突の多さや、 それを解決する困難さをよく訴えます。 しかし多くのグループの経験から言うと、 衝突は稀であり、解決も普通は比較的簡単なものです。

衝突は2人の開発者がコードの与えられた部分の適切な設計について 意見が食い違っているときにのみ起こることを理解するまで、 深刻な衝突の発生の少なさは驚きでしょう。 このような衝突は、そもそもチーム内での意思疎通が上手く行っていないこと を示しています。 どのようなソース管理方法を採るにしても、 開発者が共同で作業する際には、 システム全体の設計方針に従わなければいけません。 きちんと従っていれば、簡単にマージできる重複ばかりになるでしょう。

無条件取得が、全く不適当な場合があります。 管理下にあるファイルの形式をマージする道具が無く (例えばワード・プロセッサによるファイルや、 CAD プログラムで編集されたファイル等)、 マージ可能なデータ書式を使用するようにプログラムを変更できない場合、 悪夢のような衝突解決をするよりは、 普通は独占取得を用いて簡単に衝突を避けたほうが賢明でしょう。

上の ファイル編集者の追跡機構 で記述された監視機構は、 独占取得と無条件取得の中間的なものと考えられます。 ファイルを編集する前に、 他の誰がファイルを編集中なのか調べることができます。 これは単純に双方の同時編集を禁止するのではなく、 現況を報告し、それが問題かどうかは自分で判断してもらいます。 これを適切に使用すれば、 独占取得と無条件取得の中でも最善の選択となるでしょう。


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

This document was generated by Akihiro Sagawa on June, 15 2005 using texi2html 1.70.