[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

Advanced CVS

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Advanced%20CVS"
"j-cvsbook/AdvancedCVS"へのコメント(無し)
検索全文Elisp

さて、これまでに CVS の使いかたの基礎の考えかたとリポジトリ管理につ いて見てきました。今度は CVS を開発プロセス全体に導入するやりかたを 見ていきたいと思います。基本的な CVS の作業サイクル(checkout, update, commit, update, commit, …)は An Overview of CVS で示 しました。この章ではそのサイクルを改善し、開発者間のコミュニケーショ ンの補助・プロジェクトの活動と履歴の概要の提供・開発の別ブランチの分 離と統一・よくある作業の自動化に対し、CVS をどう役立てていくかについ て議論します。テクニックの説明のなかで新しい CVS コマンドを紹介して いることもありますが、多くは既に知っているコマンドのより良い使い方を 説明しているだけです。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16 Watches (CVS As Telephone)

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Watches%20(CVS%20As%20Telephone)"
"j-cvsbook/A.16Watches(CVSAsTelephone)"へのコメント(無し)
検索全文Elisp

プロジェクトを CVS で使用する場合の主な利点は、CVS がコミュニケーショ ン機器として、また記録係としての機能を果たすことです。この節ではプロ ジェクトの参加者に、プロジェクト内で何が起こっているかを通知するのに CVS をどう使えばよいかということを集中的に取り上げます。 **************** As is true with other aspects of CVS, these features reward cooperation. **************** 参加者は通知してもらい たいに違いありません; コミュニケーション機能を使わないなら、CVS はそ れについてなにもしないこともできます。

A.16.1 How Watches Work  
A.16.2 Enabling Watches In The Repository  
A.16.3 Using Watches In Development  
A.16.4 Ending An Editing Session  
A.16.5 Controlling What Actions Are Watched  
A.16.6 Finding Out Who Is Watching What  
A.16.7 Reminding People To Use Watches  
A.16.8 What Watches Look Like In The Repository  



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16.1 How Watches Work

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=How%20Watches%20Work"
"j-cvsbook/A.16.1HowWatchesWork"へのコメント(無し)
検索全文Elisp

CVS はデフォルトでは各作業コピーを独立したサンドボックスとして扱いま す。あなたが変更をコミットするまでは、あなたが作業コピーで何をしてい るのか、誰にもわかりません。そしてあなたも、他の人が自分の作業コピー で何をしているのかなんてわかりません、通常のコミュニケーション方法を とる以外ないのです。たとえば廊下で「ねえ、いま parse.c いじろうと思 うんだけどさ、コンフリクトすんのヤだから編集するときは教えてね!」な どと叫んだりするしか。

このような非公式なやりかたは、誰が何を担当しているか全般について皆が 知っているようなプロジェクトならうまくいきます。が、このやりかたでは 大人数の開発者がコードベースの全てをいじっていて、かつコンフリクトを 避けたいような場合にはうまくいかないでしょう。このような場合、メンバー が地理的に分散しているので、お互いの分担責任領域に頻繁に踏み込む必要 があっても廊下で叫び合うわけにはいきません。

CVS には監視(watch)と呼ばれる機能があって、ある時刻に誰がどのファ イルをいじっているかをお互いに通知し合うことができます。ある開発者が、 あるファイルを監視設定すると、他のだれかがそのファイルをいじり 始めるとその開発者に CVS から通知が来ます。その通知は普通メールで送 信されますが、他の方法に設定することもできます。

監視を使うには、リポジトリの管理エリア内のファイルを1つか2つ変更 しなければなりません。また、開発者はチェックアウト/アップデート/コミッ トのサイクルに余分な手順を加えなければなりません。リポジトリ側の変更 はごく簡単なものです: `CVSROOT/notify' ファイルを編集して、CVS がどのように通知すればいいかを設定します。`CVSROOT/users' ファ イルに電子メールアドレスの行を追加します。

作業コピー側では、開発者は CVS に対し、どのファイルを監視したい かを CVS に指示し、他の誰かがそれらのファイルを編集し始めたら CVSが 通知を送れるようにします。また、ファイルを編集し始めた時やし終わった 時には CVS にそれを知らせなければなりません。CVS はそれを受けて、そ のファイルを監視している他の人に通知します。これらの手順 を実現するコマンドを次に示します:

watchコマンドは通常の CVS コマンドのパターンとは違い、もう一 段階サブコマンドを必要とします。cvs watch add..., cvs watch remove...,などなど。

以下の例で、リポジトリ側で監視を有効にするやりかたと、開発者側で の監視の使いかたを見ていきます。2人のユーザ、jrandom と qsmith を例にとります。同じプロジェクトの作業コピーをそれぞれが持っていて、 それらは別のマシン上にあるかもしれません。全ての例において、 $CVSROOT 環境変数が設定してあると仮定しますので、cvs コマンドに -d <REPOS> をつける必要はありません。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16.2 Enabling Watches In The Repository

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Enabling%20Watches%20In%20The%20Repository"
"j-cvsbook/A.16.2EnablingWatchesInTheRepository"へのコメント(無し)
検索全文Elisp

まずは CVSROOT/notify ファイルを編集して、電子メールでの通知を有 効にします。開発者の1人がやってもいいですし、もし開発者にリポジトリ の管理ファイルを変更する権限がなければ、管理者がやってもいいです。ど ちらにしろ、まずは管理領域をチェックアウトして、それから notify ファ イルを編集します:

 
floss$ cvs -q co CVSROOT 
U CVSROOT/checkoutlist 
U CVSROOT/commitinfo 
U CVSROOT/config 
U CVSROOT/cvswrappers 
U CVSROOT/editinfo 
U CVSROOT/loginfo 
U CVSROOT/modules 
U CVSROOT/notify 
U CVSROOT/rcsinfo 
U CVSROOT/taginfo 
U CVSROOT/verifymsg 
floss$ cd CVSROOT
floss$ emacs notify 
... 

notify ファイルは、初回編集時にはこのようになっています:

 
# The "notify" file controls where notifications from watches set by 
# "cvs watch add" or "cvs edit" are sent. The first entry on a line is 
# a regular expression which is tested against the directory that the 
# change is being made to, relative to the $CVSROOT. If it matches, 
# then the remainder of the line is a filter program that should contain 
# one occurrence of %s for the user to notify, and information on its 
# standard input. 
# 
# "ALL" or "DEFAULT" can be used in place of the regular expression. 
# 
# For example: 
# ALL mail %s -s "CVS notification" 

最後の行の冒頭の#を取ってコメントをはずすだけです。notify ファ イルは他の管理ファイルと同様、ディレクトリ名に対する正規表現を書ける 柔軟なインタフェースを提供していますが、実際はその柔軟さを活用するこ とはほとんどありません。リポジトリの特定部分にマッチする正規表現を複 数行で書くことがあるとすれば、各プロジェクト用に別々の通知機構を使い たいときだけでしょう。しかし、通常の電子メールは完璧に良い通知機構な ので、大抵はそれを使います。

電子メール通知を指定するには、標準的な Unix マシンではこの行

 
ALL mail %s -s "CVS notification" 

を書けば動きます。このコマンドは通知をサブジェクトCVS notificationの電子メールで送ります(例によって、特殊表現 ALL は全て のディレクトリにマッチします)。この行のコメントをはずしたら、notify ファイルをコミットしてリポジトリに変更を知らせましょう:

 
floss$ cvs ci -m "turned on watch notification" 
cvs commit: Examining . 
Checking in notify; 
/usr/local/newrepos/CVSROOT/notify,v  <--  notify 
new revision: 1.2; previous revision: 1.1 
done 
cvs commit: Rebuilding administrative file database 
floss$  

notify ファイルをこのように編集しさえすればリポジトリの監視ができま す。しかしながら、リモートからプロジェクトに参加している開発者がいる 場合、`CVSROOT/users' ファイルも編集する必要があります。users ファイルの目的は、外部のメールアドレスを持っているユーザに対し、電子 メール通知をどこへ送信すればよいかを CVS に指示することです。users ファイルの各行の形式は:

 
CVS_USERNAME:EMAIL_ADDRESS 

です。例えば、

 
qsmith:quentinsmith@farawayplace.com 

行の冒頭の CVS ユーザ名というのは、そのユーザ名が `CVSROOT/passwd' に存在し、かつ pserver アクセスを使っている場合はそのユーザに、そうでな ければ CVS を実行している人のサーバ側のシステムユーザ名に対応します。コ ロンのあとにはそのユーザに通知を送る場合の外部のメールアドレスを書きます。 これを書いている時点では、users ファイルは CVS ディストリビューション中 に存在しません。管理ファイルなので、普通のやりかたでファイルを作成して cvs add して commit してもらって、それに加え `CVSROOT/checkoutlist' に書き足してください。こうするとリポジトリ内のチェックアウトコピーが常に 保守されるようになります。

これを行うセッションの実地例をお見せしましょう:

 
floss$ emacs checkoutlist 
  ... (add the line for the users file) ... 
floss$ emacs users 
  ... (add the line for qsmith) ... 
floss$ cvs add users 
floss$ cvs ci -m "added users to checkoutlist, qsmith to users" 
cvs commit: Examining . 
Checking in checkoutlist; 
/usr/local/newrepos/CVSROOT/checkoutlist,v  <--  checkoutlist 
new revision: 1.2; previous revision: 1.1 
done 
Checking in users; 
/usr/local/newrepos/CVSROOT/users,v  <--  users 
new revision: 1.2; previous revision: 1.1 
done 
cvs commit: Rebuilding administrative file database 
floss$  

`CVSROOT/users' にメールアドレスを拡張形式で書くこともできますが、 空白文字には注意して、全てクオートしてください。例えば、次のは動きますが:

 
qsmith:"Quentin Q. Smith "

または

 
qsmith:'Quentin Q. Smith <quentinsmith@farawayplace.com>' 

しかし、これは動きません:

 
qsmith:"Quentin Q. Smith" <quentinsmith@farawayplace.com> 

動くかどうかわからないと思う時は、 notify ファイルに指定するコマンドライ ンを手で動かしてテストしてください。下記の %s

 
mail %s -s "CVS notification" 

users ファイルのコロンのあとに書いたのと同じものに置き換えてください。コ マンドプロンプトでやってみて動いたら、users ファイルでも動きます。

これらが終わった時点で checkoutlist ファイルはこのようになっています:

 
# The "checkoutlist" file is used to support additional version controlled 
# administrative files in $CVSROOT/CVSROOT, such as template files. 
# 
# The first entry on a line is a filename which will be checked out from 
# the corresponding RCS file in the $CVSROOT/CVSROOT directory. 
# The remainder of the line is an error message to use if the file cannot 
# be checked out. 
# 
# File format: 
# 
#       [<whitespace>]<filename><whitespace><error message><end-of-line> 
# 
# comment lines begin with '#' 

users   Unable to check out 'users' file in CVSROOT. 

users ファイルはこのようになっていると思います:

 
qsmith:quentinsmith@farawayplace.com 

さて、これでリポジトリの監視用設定はできました。次に開発者が作業コピーで しなければならないことを見ていきましょう。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16.3 Using Watches In Development

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Using%20Watches%20In%20Development"
"j-cvsbook/A.16.3UsingWatchesInDevelopment"へのコメント(無し)
検索全文Elisp

開発者はまず、作業コピーをチェックアウトして、次にプロジェクト中の1ファ イルの監視者リストに自分を加えます:

 
floss$ whoami 
jrandom 
floss$ cvs -q co myproj 
U myproj/README.txt 
U myproj/foo.gif 
U myproj/hello.c 
U myproj/a-subdir/whatever.c 
U myproj/a-subdir/subsubdir/fish.c 
U myproj/b-subdir/random.c 
floss$ cd myproj 
floss$ cvs watch add hello.c 
floss$ 

最後のコマンド cvs watch add hello.c で、誰かが hello.c で作業しはじめた ら jrandom に通知するよう CVS に対し指示します(つまり、 jrandom を hello.c の監視リストに加えます)。あるファイルが編集され次第 CVS が通知を 送るするためには、編集しようとするユーザがそのファイルに対してまず cvs edit を実行する必要があります。CVS にとって、編集が始まったことを知る方 法は他にありません。チェックアウトが済んだら通常 CVS は次のアップデート かコミットまで起動されることはありませんから、そのときにはもうそのファイ ルは編集されているかもしれません:

 
paste$ whoami 
qsmith 
paste$ cvs -q co myproj 
U myproj/README.txt 
U myproj/foo.gif 
U myproj/hello.c 
U myproj/a-subdir/whatever.c 
U myproj/a-subdir/subsubdir/fish.c 
U myproj/b-subdir/random.c 
paste$ cd myproj 
paste$ cvs edit hello.c 
paste$ emacs hello.c 
... 

qsmith が cvs edit hello.c を実行したとき、CVS は hello.c の監視リストを 見て jrandom がその中にいることを知り、jrandom に対して qsmith がそのファ イルを編集しはじめたことをメールを送って知らせます。メールは qsmith から 来たようなかたちになります:

 
From: qsmith 
Subject: CVS notification 
To: jrandom 
Date: Sat, 17 Jul 1999 22:14:43 -0500 

myproj hello.c 
-- 
Triggered edit watch on /usr/local/newrepos/myproj 
By qsmith 

加えて、qsmith (またはどの人でも) が hello.c の新しいリビジョンをコミッ
トするたびに、jrandom はメールを受けとります:

myproj hello.c 
-- 
Triggered commit watch on /usr/local/newrepos/myproj 
By qsmith 

これらのメールを受けとったら、jrandom は hello.c をアップデートして qsmith が何をしたか見てみたいでしょうし、qsmith にそのファイルをいじった 理由をきくためにメールするでしょう。qsmith は cvs edit を実行するのを忘 れないように強制はされなかったことに注意してください。おそらく、自分が何 をしようとするかを jrandom に知ってもらいたかったから実行したのです(どち らにしろ、cvs edit するのを忘れていたとしても、コミットすれば通知が起こ ります)。cvs edit を使うのは、あるファイルをいじりはじめる前にそのファイ ルを監視している人たちにそれを知らせるのが目的です。監視している人たちが、 コンフリクトが起こるかもしれないと思った場合には連絡できますから、時間を 無駄にせずに済むでしょう。

あるファイルに対し cvs edit を実行した人は全てそのファイルの監視リストに 加えて欲しいと思っている(少なくとも一時的に、誰か他の人がそのファイルを 編集しはじめた場合とかには)、と CVS は仮定します。qsmith が cvs edit を 実行した場合、彼は hello.c の監視者になります。彼と jrandom は第三者が cvs edit を実行した場合(あるいはコミットした場合)、通知を受けとります。

しかし、CVS はそのファイルを編集中の人は編集している間だけ監視者リストに 居たいだろうと仮定します。そのようなユーザは編集が済んだら監視者リストか らはずされます。そのファイルをずっと監視したい場合は cvs watch add を実 行する必要があります。また、デフォルトでコミット時には編集が終わったと仮 定します(とりあえず次回までは)。

あるファイルに対し cvs edit を走らせただけで監視者リストに入っ た人は、一時監視者(temporary watcher)と呼ばれ、変更をコミットし次 第監視者リストからはずされます。そのファイルを再度編集したい場合は、 cvs edit を再実行する必要があります。

変更作業が終わるまで何回コミットする必要があるかということは CVS にはわ かりませんので、最初のコミットで編集が終わると仮定する以外に良い方法はあ りません。この仮定は1回限り(one-off)の変更の場合、つまりファイルの 1個所だけ直してコミットするなら、うまくいきます。ちょっと長いあいだ編集 して何度かコミットするような場合は、自分を恒久的に監視リストに加えたほう がよいでしょう:

 
paste$ cvs watch add hello.c 
paste$ cvs edit hello.c 
paste$ emacs hello.c 
... 
paste$ cvs commit -m "print hello in Sanskrit" 

watch add したので、qsmith はコミット後も hello.c を監視したままになりま す。(ところで、qsmith は自分が編集したことについては通知されません、他の 人にだけ通知が行きます。CVS はかしこいので、誰かがやったことをその人自身 宛に通知したりしないのです)



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16.4 Ending An Editing Session

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Ending%20An%20Editing%20Session"
"j-cvsbook/A.16.4EndingAnEditingSession"へのコメント(無し)
検索全文Elisp

コミットしたくないけど編集が終わったことを明示したい場合は、cvs unedit を実行しましょう:

 
paste$ cvs unedit hello.c 

でも、気をつけてください! こうすると、監視している人全員に編集を終えたこ とを知らせる以上のことをします。そのファイルに加えたけれどコミットしてい ない変更を、取り消すかどうか聞いてきます:

 
paste$ cvs unedit hello.c 
hello.c has been modified; revert changes? y 
paste$  

もし y と答えると、CVS は変更を全て取り消したあと、あなたがもはや そのファイルを編集中ではないということを監視者に知らせます。n と 答えると、CVS は変更をそのままに置いておき、あなたは編集者として登録され たままになります(通知はされません、つまりcvs uneditを全く実行 しなかったのと同じということになります)。キーの1打の違いで変更が全部取り 消されてしまうのはちょっとこわいような気もしますが、原則は理解しやすいと 思います: その編集を終える旨世界に宣言するということは、コミットしていな い変更を置いておく意味はない、ということです。少なくとも CVS はそのよう に理解します。おせっかいかもしれませんが、十分気をつけてくださいね!



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16.5 Controlling What Actions Are Watched

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Controlling%20What%20Actions%20Are%20Watched"
"j-cvsbook/A.16.5ControllingWhatActionsAreWatched"へのコメント(無し)
検索全文Elisp

デフォルトでは、監視している人には3種類のアクションが通知されます: edit, commit, unedit です。ですが、たとえば commit だけを通知して欲しい場合に は -a フラグ(a は action という意味)で通知のしかたを調整することができ ます:

 
floss$ cvs watch add -a commit hello.c

あるいは、edit と commit だけを監視したいけれど unedit は気にしないとい う場合には -a フラグを2つ渡してください:

 
floss$ cvs watch add -a edit -a commit hello.c 

-a フラグで監視を追加する場合、いまある監視を削除したりはしません。もし 既に3種類のアクションを hello.c について監視している場合には、

 
floss$ cvs watch add -a commit hello.c 

とやっても何の効果もありません、3種類全部を監視したままになります。監視 を削除したければ、

 
floss$ cvs watch remove hello.c 

を実行してください。add と同じように、デフォルトでは3つのアクション全て の監視を削除します。 -a 引数を渡すと、指定した監視のみを削除します:

 
floss$ cvs watch remove -a commit hello.c 

これは commit についての通知を受けとるのをやめるが、edit と unedit につ いての通知は引き続き受けとる、という意味になります(初めに edit と unedit を監視しているとすればそうなるということです)。

-a フラグに渡すアクションで、2つ特殊なものがあります: all と none です。 前者は監視できるアクション全てを意味し(これを書いている時点では edit, commit, unedit です)、後者はどれでもないという意味になります。-a がない 場合、CVS のデフォルト動作では全てのアクションを監視することになりますし、 どれも監視しないというのは監視者リストから自分を削除するというのに等しい ので、これら2つの特殊アクションを使うような状況というのは考えにくいです。 しかしながら、cvs edit は -a オプションを解釈しますので、この場合にはall または none を指定できるのは便利かもしれません。例えば、だれかがあるファ イルをとても短い間だけいじっていて、ほかの人がそのファイルで何をしている かの通知を受け取りたくないとしましょう。その場合、このコマンドを実行すると

 
paste$ whoami 
qsmith 
paste$ cvs edit -a none README.txt 

README.txt の監視者は qsmith がそのファイルをいじろうとしているという通 知を受けとりますが、qsmith は自分の編集中 README.txt の一時監視者には加 えられません(通常は加えられます)。どのアクションも監視したくないと言った からです。

cvs watch コマンドでは、自分自身の監視をいじれるだけだということを覚えて おいてください。あるファイルについて自分自身が監視するのを止めることはで きますが、誰か他の人の監視状況を変えることはできません。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16.6 Finding Out Who Is Watching What

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Finding%20Out%20Who%20Is%20Watching%20What"
"j-cvsbook/A.16.6FindingOutWhoIsWatchingWhat"へのコメント(無し)
検索全文Elisp

cvs edit を実行する前に誰が監視しているか知りたいと思うこともあるでしょ う。また、自分を監視リストに加えずに、誰が何を編集しているのか知りたいこ ともあるでしょう。あるいは、自分の状況を忘れてしまうこともあるでそう。監 視を設定/設定解除してファイルをコミットしたあとは、何を監視していて何を 編集中なのかを見失いがちです。

CVS は誰が監視していて、誰がファイルを編集中なのかを見せてくれるコマンド を2つ用意しています。cvs watchers と cvs editors です:

 
floss$ whoami 
jrandom 
floss$ cvs watch add hello.c 
floss$ cvs watchers hello.c 
hello.c jrandom  edit unedit  commit 
floss$ cvs watch remove -a unedit hello.c 
floss$ cvs watchers hello.c 
hello.c jrandom  edit commit 
floss$ cvs watch add README.txt 
floss$ cvs watchers 
README.txt      jrandom edit    unedit  commit 
hello.c jrandom edit    commit 
floss$  

最後の cvs watchers コマンドはファイルを指定していないことに注意して ください。従って、すべてのファイルの監視者を表示します(つまり、監視 者のいるファイルをすべて、ということです)。

他の CVS コマンドと同様、すべての watch コマンドと edit コマンドはこ のように動作します。ファイル名を指定した場合、そのファイルについて動 作します。ディレクトリ名を指定した場合、そのディレクトリとそのサブディ レクトリ内のすべてについて動作します。何も指定しない場合、カレントディ レクトリとそれ以下できる限り深いレベルまですべてについて動作します。 たとえば(同じセッションを続けます):

 
floss$ cvs watch add a-subdir/whatever.c  
floss$ cvs watchers 
README.txt      jrandom edit    unedit  commit 
hello.c jrandom edit    commit 
a-subdir/whatever.c     jrandom edit    unedit  commit 
floss$ cvs watch add 
floss$ cvs watchers 
README.txt      jrandom edit    unedit  commit 
foo.gif jrandom edit    unedit  commit 
hello.c jrandom edit    commit  unedit 
a-subdir/whatever.c     jrandom edit    unedit  commit 
a-subdir/subsubdir/fish.c       jrandom edit    unedit  commit 
b-subdir/random.c       jrandom edit    unedit  commit 
floss$  

コマンドの最後2つはそれぞれ、 jrandom をプロジェクト中のすべてのファ イルの監視者にし、プロジェクト中の全ファイルの監視者リストを表示して います。cvs watchers の出力は可変長の情報とタブストップが 混合しているので、カラムがいつも完璧に整列しているわけではありません。 しかし、各行は一貫した形式になっています:

 
[FILENAME] [whitespace] WATCHER [whitespace] ACTIONS-BEING-WATCHED... 

さて、qsmith がファイルをひとつ編集し始めたとして、何が起こるか見て みましょう:

 
paste$ cvs edit hello.c 
paste$ cvs watchers 
README.txt      jrandom edit    unedit  commit 
foo.gif jrandom edit    unedit  commit 
hello.c jrandom edit    commit  unedit 
       qsmith  tedit   tunedit tcommit 
a-subdir/whatever.c     jrandom edit    unedit  commit 
a-subdir/subsubdir/fish.c       jrandom edit    unedit  commit 
b-subdir/random.c       jrandom edit    unedit  commit 

hello.c にはもう一人監視者が増えました: qsmith です(ファイル名は繰り 返されませんが、行の冒頭は空白文字になっていることに注意してください。 このことは watchers の出力を読むプログラムを書くときに重要になるでしょ う) hello.c を編集しているので、qsmith はそのファイルを 一時監 視 していることになります。ただし彼が hello.c の新しいリビジョンを コミットするとそうではなくなってしまいます。各アクションの前にあるプ レフィクス t は、これらが一時監視であることを示します。 qsmith がまた、自分自身を hello.c の正規監視者とした場合

 
paste$ cvs watch add hello.c 
README.txt      jrandom edit    unedit  commit 
foo.gif jrandom edit    unedit  commit 
hello.c jrandom edit    commit  unedit 
       qsmith  tedit   tunedit tcommit edit    unedit  commit 
a-subdir/whatever.c     jrandom edit    unedit  commit 
a-subdir/subsubdir/fish.c       jrandom edit    unedit  commit 
b-subdir/random.c       jrandom edit    unedit  commit 

彼は、一時監視者かつ常時監視者であると表示されます。常時監視状態は一 時監視をオーバライドして次のようになると思ったかもしれませんが:

 
        qsmith  edit    unedit  commit 

しかし、どんな順序で起こるかわからないので CVS は一時監視を置き換え ることはできません。qsmith が編集を終わる前に常時監視をやめたとした ら? あるいは監視したままで編集を終えたとしたら? 前者の場合、tedit/ tunedit/tcommit アクションを残したままedit/unedit/commit アクション は削除されます。後者の場合、逆になります。

とにかく、通常は監視者リスト側のことはあまり気にすることはありません。 たいていはプロジェクトのトップレベルで

 
floss$ cvs watchers 

 
floss$ cvs editors 

を実行し、誰が何をしているか見ればよいのです。誰がどのアクションに注 意しているか、詳細を知る必要はありません、重要なのは人とファイルです。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16.7 Reminding People To Use Watches

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Reminding%20People%20To%20Use%20Watches"
"j-cvsbook/A.16.7RemindingPeopleToUseWatches"へのコメント(無し)
検索全文Elisp

監視機構は開発者全員の協力に全面的に依存しているということに、既にお 気づきだと思います。誰かが cvs edit をし忘れてファイルを編集し始めた 場合、変更がコミットされるまで、誰もそのことを知らないということになっ てしまいます。cvs edit というのは通常の開発のサイクルに入っておらず、 余分に手数のかかるものですから、忘れやすいと言えるでしょう。

CVS は cvs edit を使うよう強制はできませんが、そうするのを忘れないよ うな機構を持っています。それは、watch on コマンドです:

 
floss$ cvs -q co myproj 
U myproj/README.txt 
U myproj/foo.gif 
U myproj/hello.c 
U myproj/a-subdir/whatever.c 
U myproj/a-subdir/subsubdir/fish.c 
U myproj/b-subdir/random.c 
floss$ cd myproj 
floss$ cvs watch on hello.c 
floss$ 

jrandom が cvs watch on hello.c を実行すると、これ以降の myproj のチェッ クアウトにおいて、作業コピー中の hello.c は読み出し専用で作成される ようになります。qsmith がそれをいじろうとすると、hello.c は読み出し 専用であることに気づき、まず cvs edit を実行することを思い出します:

 
paste$ cvs -q co myproj 
U myproj/README.txt 
U myproj/foo.gif 
U myproj/hello.c 
U myproj/a-subdir/whatever.c 
U myproj/a-subdir/subsubdir/fish.c 
U myproj/b-subdir/random.c 
paste$ cd myproj 
paste$ ls -l 
total 6 
drwxr-xr-x   2 qsmith    users        1024 Jul 19 01:06 CVS/ 
-rw-r--r--   1 qsmith    users          38 Jul 12 11:28 README.txt 
drwxr-xr-x   4 qsmith    users        1024 Jul 19 01:06 a-subdir/ 
drwxr-xr-x   3 qsmith    users        1024 Jul 19 01:06 b-subdir/ 
-rw-r--r--   1 qsmith    users         673 Jun 20 22:47 foo.gif 
-r--r--r--   1 qsmith    users         188 Jul 18 01:20 hello.c 
paste$ 

こうすると、ファイルは読み書きできるようになります。編集してコミット すると、また読み出し専用になります:

 
paste$ cvs edit hello.c 
paste$ ls -l hello.c 
-rw-r--r--   1 qsmith    users         188 Jul 18 01:20 hello.c 
paste$ emacs hello.c 
  ...  
paste$ cvs commit -m "say hello in Aramaic" hello.c 
Checking in hello.c;  
/usr/local/newrepos/myproj/hello.c,v  <--  hello.c 
new revision: 1.12; previous revision: 1.11 
done 
paste$ ls -l hello.c 
-r--r--r--   1 qsmith    users         210 Jul 19 01:12 hello.c 
paste$  

彼の edit と commit は hello.c の監視者全員に通知されます。jrandom は監視者でなくてもかまわないことに注意してください。cvs watch on hello.c を実行しても、jrandom はそのファイルの監視者リストの一員になっ たりはしないのです。ただ読み出し専用でチェックアウトされるように指定 しただけになります。ファイルを監視したい人は自分を監視者リストに加え るのを忘れないようにする必要があります。CVS はその面倒は見ません。

ファイルひとつについて watch on するのは例外的な状況です。一般にはプ ロジェクト全体を watch on するのが普通です:

 
floss$ cvs -q co myproj 
U myproj/README.txt 
U myproj/foo.gif 
U myproj/hello.c 
U myproj/a-subdir/whatever.c 
U myproj/a-subdir/subsubdir/fish.c 
U myproj/b-subdir/random.c 
floss$ cd myproj 
floss$ cvs watch on 
floss$  

このアクションはプロジェクト全体についてのポリシーをアナウンスするの に等しいです: 「ファイルをいじるときは cvs edit を使って監視してる人 に知らせてね。興味があったり、担当のファイルは自由に監視してください」 プロジェクト中の全ファイルは読み出し専用でチェックアウトされますので、 何かいじろうとすると cvs edit をしなければならないのを思い出すことで しょう。

おもしろいことに、監視されているファイルをチェックアウトすると読み出 し専用になるのに、アップデートではそうはなりません。jrandom が cvs watch on する前に既に qsmith が作業コピーをチェックアウトしていたと すると、qsmith のファイルはアップデートしても読み書きできるままにな ります。しかし、jrandom が watch on した後でコミットしたファイルは読 み出し専用になります。jrandom が watch off しても、

 
floss$ cvs watch off 

qsmith の読み出し専用ファイルは自動的に読み書きできるようになったり はしません。一方、コミット後に読み出し専用には戻らなくなります(watch on のままだと読み出し専用に戻ります)。qsmith がひねくれていて、 cvs edit を全く避けて chmod コマンドで作業コピー中 のファイルを書込み可にしたとします

 
paste$ chmod u+w hello.c 

またはこのように全部一挙に

 
paste$ chmod -R u+w . 

したとします。

こういう風なことをされると CVS には手も足も出ません。もともと作業コ ピーというのはプライベートなサンドボックスなのです。監視機構は the watch features can open them up to public scrutiny a little bit, but only as far as the developer permits. Only when a developer does something that affects the repository (such as commits) is her privacy unconditionally lost.

watch add, watch remove, watch on, watch off の関係はちょっとわかり にくいかもしれません。全体の規則をまとめるとこうなります:

addremove はそのファイルの監視者リストにユーザを追 加したり、削除したりするもので、チェックアウト時やチェックアウト後に ファイルを読み出し専用にしたりはしません。onoff は ファイルのパーミッションについてのものです。ファイルの監視者リストに 居るユーザをどうこうしたりはしません。開発者に監視ポリシーを思い出し てもらうために作業コピー中のファイルを読み出し専用にするだけです。

ちょっと一貫していないように見えるかもしれません。監視機構を使うとい うのは、ある意味で CVS の本質に反しています。複数の開発者が自分の作 業コピー内で自由に編集し、そのことはコミットするまでお互いから見えな い、という理想世界からそれることになります。監視機構は開発者が自分の 作業コピーで何をしているかお互いに知らせるために CVS が提供している 便利な方法なのです。しかし監視ポリシーを強制する方法はありませんし、 編集セッションがどのように構成されるかについて絶対的なコンセプトがあ るわけでもありません。まあそれでも監視機構が役に立つような状況もある のです。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.16.8 What Watches Look Like In The Repository

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=What%20Watches%20Look%20Like%20In%20The%20Repository"
"j-cvsbook/A.16.8WhatWatchesLookLikeInTheRepository"へのコメント(無し)
検索全文Elisp

ブラックボックスと要らぬ神秘を打ち消すため、リポジトリ中で監視機構が どう実装されているかちょっと覗いてみることにしましょう。でも pretty ではないので、ほんとにちょっと覗くだけですよ。

監視するよう設定すると

 
floss$ pwd 
/home/jrandom/myproj 
floss$ cvs watch add hello.c 
floss$ cvs watchers 
hello.c jrandom edit    unedit  commit 
floss$ 

CVS は適切なリポジトリのサブディレクトリ中のある特殊なファイル `CVS/fileattr' にそれを記録します:

 
floss$ cd /usr/local/newrepos 
floss$ ls 
CVSROOT/   myproj/ 
floss$ cd myproj 
floss$ ls 
CVS/          a-subdir/     foo.gif,v 
README.txt,v  b-subdir/     hello.c,v 
floss$ cd CVS 
floss$ ls 
fileattr 
floss$ cat fileattr 
Fhello.c        _watchers=jrandom>edit+unedit+commit 
floss$  

リポジトリに中の CVS サブディレクトリに fileattr が保存されるからと いって、リポジトリが作業コピーになったわけではありません。単に、 CVS という名前が既に作業コピー中で図書管理用に予約されているの で、リポジトリ中にその名前のサブディレクトリを作るようなプロジェクト は存在しないというのを確信できるから、という理由によります。

`fileattr' の形式をきちんと説明したりはしません。コマンドごとに そのファイルが変わるのを見るだけで理解できると思います。

 
floss$ cvs watch add hello.c 
floss$ cat /usr/local/newrepos/myproj/CVS/fileattr 
Fhello.c        _watchers=jrandom>edit+unedit+commit 
floss$ cvs watch add README.txt 
floss$ cat /usr/local/newrepos/myproj/CVS/fileattr 
Fhello.c        _watchers=jrandom>edit+unedit+commit 
FREADME.txt     _watchers=jrandom>edit+unedit+commit 
floss$ cvs watch on hello.c 
floss$ cat /usr/local/newrepos/myproj/CVS/fileattr 
Fhello.c        _watchers=jrandom>edit+unedit+commit;_watched= 
FREADME.txt     _watchers=jrandom>edit+unedit+commit 
floss$ cvs watch remove hello.c 
floss$ cat /usr/local/newrepos/myproj/CVS/fileattr 
Fhello.c        _watched= 
FREADME.txt     _watchers=jrandom>edit+unedit+commit 
floss$ cvs watch off hello.c 
floss$ cat /usr/local/newrepos/myproj/CVS/fileattr 
FREADME.txt     _watchers=jrandom>edit+unedit+commit 
floss$  

fileattr 中のレコードを編集してみたりしましょう。qsmith が自分自身を 編集者として登録したときに起こることを見てみます:

 
paste$ cvs edit hello.c 

floss$ cat /usr/local/newrepos/myproj/CVS/fileattr 
Fhello.c        _watched=;_editors=qsmith>Tue Jul 20 04:53:23 1999 GMT+floss\
+/home/qsmith/myproj;_watchers=qsmith>tedit+tunedit+tcommit 
FREADME.txt     _watchers=jrandom>edit+unedit+commit 

そのディレクトリのファイル全部に監視者も編集者もいなくなると、CVS は fileattr ファイルも CVS サブディレクトリも削除してしまうことに注 意して下さい:

 
paste$ cvs unedit 

floss$ cvs watch off 
floss$ cvs watch remove 
floss$ cat /usr/local/newrepos/myproj/CVS/fileattr 
cat: /usr/local/newrepos/myproj/CVS/fileattr: No such file or directory 
floss$  

こうやってちょっと見てみるとおわかりの通り、fileattr のフォーマット の解釈の詳細は CVS に任せておいたほうがよいです。

そのフォーマットについて理解するのは、舞台裏でなにが起こっているのか 知って満足するというのを置いておくとすると、CVS の監視機構の拡張を書 くとか、そのへんをデバッグするとかが主な理由だと思います。普通はリポ ジトリの中に CVS/ サブディレクトリができたからといってびっくりしない 程度で十分です。CVS/ サブディレクトリは CVS にとって、監視者リストの ようなメタ情報を安全に保存しておける唯一の場所なのです。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.17 Log Messages And Commit Emails

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Log%20Messages%20And%20Commit%20Emails"
"j-cvsbook/A.17LogMessagesAndCommitEmails"へのコメント(無し)
検索全文Elisp

コミットメールとはコミット時に送信される通知で、ログメッセージやその コミットに含まれるファイル情報などを示します。通常はプロジェクトの参 加者全員に送信されます。そのプロジェクトに興味のある他の人々に送られ ることもあります。コミットメールの設定方法の詳細は Repository Administration で説明しましたのでここでは繰り返しません。

take into account 考慮に入れる

I have noticed, however, that commit emails can sometimes result in unexpected side effects to projects, effects that you may want to take into account if you set up commit emails for your project.

まず、メッセージは大概無視されることを覚悟して下さい。読まれるかどう かは、少なくとも部分的には、そのプロジェクトにおいてどのくらいの頻度 でコミットが行われるかによります。開発者は一日の終わりに1回だけ大き な変更をコミットするのでしょうか、それとも一日を通して小さな変更をた くさんコミットするのでしょうか? プロジェクトが後者に近いようなら、一 日中さみだれのようにやってくる小さな通知に対して開発者は壁を作ってし まうでしょうし、各メッセージに対して払う注意も小さくなるでしょう。

これは別に通知が役に立たないという意味ではないです、ただみんながメッ セージを全部読んでいるはずだなんて思っちゃいけないというだけのことで す。皆に誰が何をしているかを見張ってもらう方法(監視リストに追加する 以外で)としては依然便利なものです。誰でも購読できるメーリングリスト を送信先にすると、興味のあるユーザ(と未来の開発者)に、日常的にコード に何が起こっているかを知る機会を与える素晴らしい機構になります。

すべてのログメッセージを見ていて、プロジェクト全体の活動について概要 を知っている開発者がいるんだ、と考えたいだろうと思います(もちろん良 きプロジェクトリーダというものは何らかの手段でこういうことをしている のだろうと思います)。明確な分担区分がある場合、つまり、ある開発者が プロジェクト中のあるサブディレクトリの係りである、ということなんです が、その場合は CVSROOT/loginfo をちょっといじって、分担領域で変更が 行われたら、係の部隊が特別に印をつけた変更通知を受け取るようにもでき ます。これは、開発者が少なくとも自分のサブディレクトリに関係あるメー ルは読むよう保証するのに役に立つでしょう。

コミットメールが無視されない場合、おもしろい副作用が起こります。リア ルタイムのコミュニケーションの手段として使われ始めるのです。そうなっ た場合のログメッセージの例をお見せしましょう:

 
Finished feedback form; fixed the fonts and background colors on the
home page.  Whew!  Anyone want to go to Mon Lung for lunch?

別に何も悪いことはないですし、あとでログメッセージを読むと楽しいでしょ うね。でも、以下の例のようなログメッセージには注意しなければなりません。 ログメッセージは電子メールで配られるだけのものではなく、プロジェクト の履歴として永久に保存されるものなのです。顧客の仕様についてのグチを 言ったりするのは、プログラマの間で気晴らしによく行われることです。他 のプログラマがメールですぐ見るとわかっている場合、こんなログメッセー ジをコミットしてしまうのは想像に難くないでしょう:

 
Truncate four-digit years to two-digits in input.  What the customer
wants, the customer gets, no matter how silly & wrong.  Sigh.
(訳: 入力時の4桁の年を2桁に縮める。お客様は御所望のものを手に入れる、
どんなにバカみたいだろうが間違ってようが気にしない。はー。)

これはおもしろいメールにはなりますが、しかし顧客が後日このログをレビュー したらどうなりますか? (これと同じような問題のために、1つ以上のサイト で、ログメッセージに不快な単語が入らないようガードするスクリプトが起 動するように CVSROOT/loginfo が設定されているのに賭けますよ!)

コミットメールの一般的な効果は、短く不明瞭なログメッセージを書きにく くなるということです。良いことだと思います。しかし、聴衆はコミットメー ルを受け取る人だけではなく、ログを読むかもしれない人全員である、とい うことに留意する必要があります。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.18 Changing A Log Message After Commit

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Changing%20A%20Log%20Message%20After%20Commit"
"j-cvsbook/A.18ChangingALogMessageAfterCommit"へのコメント(無し)
検索全文Elisp

後悔するようなログメッセージをコミットしてしまった場合には、CVS では コミットしたあとでそのログを書き直すことができます。これは admin コ マンドの -m オプションででき(このコマンドについてはこの章のもう少し 後で説明します)、一度に1つのログメッセージ(リビジョン毎、ファイル毎) を変更できます。どのように動くか見てみましょう:

 
floss$ cvs admin -m 1.7:"Truncate four-digit years to two in input." date.c 
RCS file: /usr/local/newrepos/someproj/date.c,v 
done 
floss$  

リビジョン1.7とともにコミットされた元の無礼なログメッセージは、完璧 に無垢なメッセージ(退屈にはなりましたが)に置き換えられました。(リビ ジョン番号と新しいログメッセージの間のコロンを忘れないようにして下さ い。)

複数のファイルに良くないメッセージがコミットされてしまった場合、1つ ずつ cvs admin を実行しなければなりません。各ファイルでリビジョン番 号が違うからです。ですから、これは CVS では数少ない、引数にファイル 名を1つだけ渡すコマンドなのです:

 
floss$ cvs admin -m 1.2:"very boring log message" hello.c README.txt foo.gif
cvs admin: while processing more than one file: 
cvs [admin aborted]: attempt to specify a numeric revision 
floss$  

まぎらわしいことに、ファイル名を渡さなかった場合にも同じエラーになり ます(なぜならそのような場合にはカレントディレクトリ及びそれ以下にあ るすべてのファイルを指定したことになるからです):

 
floss$ cvs admin -m 1.2:"very boring log message" 
cvs admin: while processing more than one file: 
cvs [admin aborted]: attempt to specify a numeric revision 
floss$  

(このように不幸にも CVS のエラーメッセージが出てしまった場合には、 CVS の視点に立ってそのメッセージの意味を読み取らねばなりません。)

admin -m を実行すると、そのプロジェクトの履歴を変えてしま うことになるので注意して使って下さい。ログメッセージが変更されたとい う記録は残りません。ただ、そのリビジョンは最初からその新しいメッセー ジでコミットされたかのように見えるのです。古いログメッセージの痕跡は どこにも残されません(元のコミットメールをセーブしているのでなければ)。

名前からするとこのコマンドは指定された CVS の管理者にしか使えないよ うに見えますが、実際は、そのプロジェクトの書込み権限さえあれば誰でも cvs admin を実行することができます。それでもやはり注意し て使うのが一番良いでしょう。プロジェクトの履歴を変えられるというのは 他の有害なものに匹敵するようなことができてしまいます。 admin については CVS Reference に詳しいです。使用を制限 する方法も書いてあります。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.19 Getting Rid Of A Working Copy

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Getting%20Rid%20Of%20A%20Working%20Copy"
"j-cvsbook/A.19GettingRidOfAWorkingCopy"へのコメント(無し)
検索全文Elisp

CVS の典型的な使い方では、作業コピーのディレクトリを削除するには、他 のディレクトリツリーと同じように削除します:

 
paste$ rm -rf myproj 

しかしこの方法で作業コピーを削除すると、その作業コピーを使い終わった ことが他の開発者にわかりません。CVS は明示的に作業コピーを放棄するコ マンドを用意しています。リリース(release)はチェックアウトの反対だと 思って下さい。その作業コピーでの作業が終わったことをリポジトリに知ら せます。チェックアウトと同様、リリースはツリーの親ディレクトリで起動 します:

 
paste$ pwd 
/home/qsmith/myproj 
paste$ cd .. 
paste$ ls 
myproj 
paste$ cvs release myproj 
You have [0] altered files in this repository. 
Are you sure you want to release directory 'myproj': y 
paste$  

リポジトリ中に未コミットの変更があった場合リリースは失敗し、変更のあ るファイルの一覧を出力する以外何もしません。そのディレクトリツリーが クリーン(すべて最新)だとするとリリースコマンドはその作業コピーがリリー スされたという記録をリポジトリ中に残します。

リリースコマンドに作業コピーのツリーを自動的に削除させることもできま す。-d フラグを渡して下さい:

 
paste$ ls 
myproj 
paste$ cvs release -d myproj 
You have [0] altered files in this repository. 
Are you sure you want to release (and delete) directory 'myproj: y 
paste$ ls 
paste$  

CVS バージョン 1.10.6 現在、リリースコマンドは作業コピーを調べてリポ ジトリの場所を推定することができません(このコマンドが作業コピーの中 ではなくその上で実行されるものだからです)。-d <REPOS> グ ローバルオプションを渡すか、 CVSROOT 環境変数が正しく設定されている ことを確認するかして下さい。(このバグは将来のバージョンの CVS では解 決されているでしょう)

Cederqvist では、作業コピーを削除する代わりにリリースを使った場合、 リリースされたファイルに監視設定をしている人々には unedit を したかのような通知が行く、と書いてあります。しかしながら筆者が試しに やってみたところ、そうはならないようでした。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.20 History -- A Summary Of Repository Activity

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=History%20--%20A%20Summary%20Of%20Repository%20Activity"
"j-cvsbook/A.20History--ASummaryOfRepositoryActivity"へのコメント(無し)
検索全文Elisp

Repository Administration で、cvs history コマンドについて少し 述べました。このコマンドはそのリポジトリで行われた全ての checkout, commit, update, rtag, release の概略を表示します(少なくとも CVSROOT/history ファイルが作成されてログの記録が始まって以降のものは)。 この概略の形式と内容は、いろいろなオプションによって変えることができ ます。

まずはリポジトリ中でログが記録できるようになっていることを確認します。 リポジトリ管理者は最初に history ファイルが存在することを確かめなく てはなりません:

 
floss$ cd /usr/local/newrepos/CVSROOT 
floss$ ls -l history 
ls: history: No such file or directory 
floss$  

ない場合には次のように作成して下さい:

 
floss$ touch history 
floss$ ls -l history 
-rw-r--r--   1 jrandom   cvs           0 Jul 22 14:57 history 
floss$  

この history ファイルはリポジトリを使用する人全員が書き込めるように なっていなければなりません。そうしないとそのファイルを変更する CVS コマンドを実行するたびにエラーが起きるようになってしまいます。ワール ドライタブルにするのが一番簡単でしょう:

 
floss$ chmod a+rw history 
floss$ ls -l history 
-rw-rw-rw-   1 jrandom   cvs           0 Jul 22 14:57 history 
floss$  

リポジトリが cvs init により作成されたのであれば history ファイルは既に存在しているはずですが、パーミッションの問題は解決する 必要があるかもしれません。

以降の例では、しばらくの間 hisotry ログ記録がされていたと仮定します。 history ファイルにデータが蓄積されるだけの時間がたっています。(?)

cvs history の出力は少々ぶっきらぼうです(これは多分、人間が読むため というよりはプログラムが解釈するためにこうなっているのでしょうけれど、 ちょっと勉強すれば読めます)。とりあえず走らせてみて出力を見てみましょ う:

 
paste$ pwd 
/home/qsmith/myproj 
paste$ cvs history -e -a 
O 07/25 15:14 +0000 qsmith  myproj =mp=     ~/* 
M 07/25 15:16 +0000 qsmith  1.14 hello.c    myproj == ~/mp 
U 07/25 15:21 +0000 qsmith  1.14 README.txt myproj == ~/mp 
G 07/25 15:21 +0000 qsmith  1.15 hello.c    myproj == ~/mp 
A 07/25 15:22 +0000 qsmith  1.1  goodbye.c  myproj == ~/mp 
M 07/25 15:23 +0000 qsmith  1.16 hello.c    myproj == ~/mp 
M 07/25 15:26 +0000 qsmith  1.17 hello.c    myproj == ~/mp 
U 07/25 15:29 +0000 qsmith  1.2  goodbye.c  myproj == ~/mp 
G 07/25 15:29 +0000 qsmith  1.18 hello.c    myproj == ~/mp 
M 07/25 15:30 +0000 qsmith  1.19 hello.c    myproj == ~/mp 
O 07/23 03:45 +0000 jrandom myproj =myproj= ~/src/* 
F 07/23 03:48 +0000 jrandom        =myproj= ~/src/* 
F 07/23 04:06 +0000 jrandom        =myproj= ~/src/* 
M 07/25 15:12 +0000 jrandom 1.13 README.txt myproj == ~/src/myproj 
U 07/25 15:17 +0000 jrandom 1.14 hello.c    myproj == ~/src/myproj 
M 07/25 15:18 +0000 jrandom 1.14 README.txt myproj == ~/src/myproj 
M 07/25 15:18 +0000 jrandom 1.15 hello.c    myproj == ~/src/myproj 
U 07/25 15:23 +0000 jrandom 1.1  goodbye.c  myproj == ~/src/myproj 
U 07/25 15:23 +0000 jrandom 1.16 hello.c    myproj == ~/src/myproj 
U 07/25 15:26 +0000 jrandom 1.1  goodbye.c  myproj == ~/src/myproj 
G 07/25 15:26 +0000 jrandom 1.17 hello.c    myproj == ~/src/myproj 
M 07/25 15:27 +0000 jrandom 1.18 hello.c    myproj == ~/src/myproj 
C 07/25 15:30 +0000 jrandom 1.19 hello.c    myproj == ~/src/myproj 
M 07/25 15:31 +0000 jrandom 1.20 hello.c    myproj == ~/src/myproj 
M 07/25 16:29 +0000 jrandom 1.3  whatever.c myproj/a-subdir == ~/src/myproj 
paste$  

There, isn't that clear?

出力を調べる前に、起動時のオプション(-e と -a)に注意して下さい。 history を実行するときには大抵、どのデータをどのように表示するか指定 するオプションをつけると思います。この点においてこのコマンドは他の CVS のコマンドとは違います。他のコマンドは普通、オプション無しでも役 に立ちます。この例の2つのフラグはそれぞれ、everything (起こったイベン トの全種類を表示) と all (全てのユーザについて) という意味です。

history コマンドが他のコマンドと違う点は他にもあって、普通このコマン ドは作業コピー内で実行しますが、コマンド出力はその作業コピーのプロジェ クトの情報に限定されません。リポジトリ内の全てのプロジェクトの全ての イベント履歴を表示します。作業コピーは履歴データをどのリポジトリから 取ってくればよいかを CVS に指定するために使われるだけです。(上の例で はリポジトリの履歴データは myproj プロジェクトのものしかない ので、これで全てなのです)

出力の形式は通常このようです:

 
CODE DATE USER [REVISION] [FILE] PATH_IN_REPOSITORY ACTUAL_WORKING_COPY_NAME

コード文字は CVS のさまざまなオペレーションを指します Table 6.1 を参 照してください。

オペレーション(チェックアウトのような)は各ファイルではなくプロジェク ト全体についてのもので、リビジョンやファイル名は省略されています。イ コール記号の間にリポジトリ内パスが書いてあります。

history コマンドの出力はコンパクトなように、他のプログラムが解釈し易 いようにデザインされていますが、CVS still gives you a lot of control over its scope and content. Table 6.2 にあるオプションで、どんなタイ プのイベントを報告して欲しいかコントロールします。

 
Table 6.1  コード文字の意味

Letter	        Meaning
======          =========================================================
O		チェックアウト
T		タグ
F		リリース
W		アップデート(ユーザファイルがない、エントリファイルから削除)
U		アップデート(変更されていないユーザファイルを上書き)
G		アップデート(変更されたユーザファイルにマージ、成功)
C		アップデート(変更されたユーザファイルにマージ、コンフリクト)
M		コミット(ファイル変更)
A		コミット(ファイル追加)
R		コミット(ファイル削除)
E		エクスポート

 
Table 6.2  イベントタイプでフィルタリングするオプション

Option	        Meaning
==========      =========================================================
-m MODULE	MODULE に起こった履歴イベントを表示
-c		コミットイベントを表示
-o		チェックアウトイベントを表示
-T		タグイベントを表示
-x CODE(S)	CODE タイプのイベントを全て表示(OTFWUGCMARE から1つ以上)
-e		全タイプのイベント表示。以上。レポートして欲しいイベン
		トのタイプを選択したあと、Table 6.3 に示したオプション
		でさらにフィルタリングすることもできます。

 
Table 6.3  ユーザでフィルタリングするオプション

Option	        Meaning
==========      =========================================================
-a		全ユーザのアクションを表示
-w		この作業コピー内のアクションのみ表示
-l		ユーザが取ったそのアクションの最後の日付を表示
-u USER 	USER の記録を表示



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.21 Annotations -- A Detailed View Of Project Activity

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Annotations%20--%20A%20Detailed%20View%20Of%20Project%20Activity"
"j-cvsbook/A.21Annotations--ADetailedViewOfProjectActivity"へのコメント(無し)
検索全文Elisp

The annotate Command

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=The%20annotate%20Command"
"j-cvsbook/TheannotateCommand"へのコメント(無し)
検索全文Elisp

history コマンドがプロジェクトの活動を表示するものだとすると、 annotate コマンドはそれにズームレンズをつけるものだと言えます。 annotate を使うとあるファイルの各行を最後に触った人が誰か、ど のリビジョンで触ったかまでわかるのです:

 
floss$ cvs annotate
Annotations for README.txt 
*************** 
1.14         (jrandom  25-Jul-99): blah 
1.13         (jrandom  25-Jul-99): test 3 for history 
1.12         (qsmith   19-Jul-99): test 2 
1.11         (qsmith   19-Jul-99): test 
1.10         (jrandom  12-Jul-99): blah 
1.1          (jrandom  20-Jun-99): Just a test project. 
1.4          (jrandom  21-Jun-99): yeah. 
1.5          (jrandom  21-Jun-99): nope. 
Annotations for hello.c 
*************** 
1.1          (jrandom  20-Jun-99): #include <stdio.h> 
1.1          (jrandom  20-Jun-99):  
1.1          (jrandom  20-Jun-99): void 
1.1          (jrandom  20-Jun-99): main () 
1.1          (jrandom  20-Jun-99): { 
1.15         (jrandom  25-Jul-99):   /* another test for history */ 
1.13         (qsmith   19-Jul-99):   /* random change number two */ 
1.10         (jrandom  12-Jul-99):   /* test */ 
1.21         (jrandom  25-Jul-99):   printf ("Hellooo, world!\n"); 
1.3          (jrandom  21-Jun-99):   printf ("hmmm\n"); 
1.4          (jrandom  21-Jun-99):   printf ("double hmmm\n"); 
1.11         (qsmith   18-Jul-99):   /* added this comment */ 
1.16         (qsmith   25-Jul-99):   /* will merge these changes */ 
1.18         (jrandom  25-Jul-99):   /* will merge these changes too */ 
1.2          (jrandom  21-Jun-99):   printf ("Goodbye, world!\n"); 
1.1          (jrandom  20-Jun-99): } 
Annotations for a-subdir/whatever.c 
*************** 
1.3          (jrandom  25-Jul-99): /* A completely non-empty C file. */
Annotations for a-subdir/subsubdir/fish.c 
*************** 
1.2          (jrandom  25-Jul-99): /* An almost completely empty C file. */ 
Annotations for b-subdir/random.c 
*************** 
1.1          (jrandom  20-Jun-99): /* A completely empty C file. */ 
floss$  

annotate の出力はとても直観的です。左側は、その行が追加、または最後 に変更されたリビジョン番号、開発者、日付です。右側は現在のリビジョン のその行自体です。全ての行に注釈がついているので、そのファイルの内容 全体を見ようと思えば、注釈情報を無視して右側だけ見ればよいのです。

リビジョン番号かタグを指定すれば、そのリビジョンについての注釈が表示 されます。各行についてそのリビジョン以前の最も最近の変更が表示される、 ということです。ある1つのファイルの特定のリビジョンを調べ、どの開発 者がファイル中のどの部分で活動したかはっきりさせる、というのが annotate の最も普通の使い道です。

例えば上の例の出力で、hello.c の最新のリビジョンは 1.21 で、jrandom がこの行:

 
printf ("Hellooo, world!\n"); 

に何かした、というのがわかると思います。

なにをしたか調べるにはは、そのリビジョンと一つ前のリビジョンの diff を取ってみるのが1つの方法です:

 
floss$ cvs diff -r 1.20 -r 1.21 hello.c 
Index: hello.c 
=================================================================== 
RCS file: /usr/local/newrepos/myproj/hello.c,v 
retrieving revision 1.20 
retrieving revision 1.21 
diff -r1.20 -r1.21 
9c9 
<   printf ("Hello, world!\n"); 
-- 
>   printf ("Hellooo, world!\n"); 
floss$  

もう一つの方法は、現在の注釈を一つ前のリビジョンの注釈と比較すること です。ファイル全体での全員の活動を見たままで調べられます。

 
floss$ cvs annotate -r 1.20 hello.c 
Annotations for hello.c 
*************** 
1.1          (jrandom  20-Jun-99): #include <stdio.h> 
1.1          (jrandom  20-Jun-99):  
1.1          (jrandom  20-Jun-99): void 
1.1          (jrandom  20-Jun-99): main () 
1.1          (jrandom  20-Jun-99): { 
1.15         (jrandom  25-Jul-99):   /* another test for history */ 
1.13         (qsmith   19-Jul-99):   /* random change number two */ 
1.10         (jrandom  12-Jul-99):   /* test */ 
1.1          (jrandom  20-Jun-99):   printf ("Hello, world!\n"); 
1.3          (jrandom  21-Jun-99):   printf ("hmmm\n"); 
1.4          (jrandom  21-Jun-99):   printf ("double hmmm\n"); 
1.11         (qsmith   18-Jul-99):   /* added this comment */ 
1.16         (qsmith   25-Jul-99):   /* will merge these changes */ 
1.18         (jrandom  25-Jul-99):   /* will merge these changes too */ 
1.2          (jrandom  21-Jun-99):   printf ("Goodbye, world!\n"); 
1.1          (jrandom  20-Jun-99): } 
floss$  

diff ではテキストの変更がより簡潔に示されますが、annotate では the annotation may be preferable because it places them in their historical context by showing how long the previous incarnation of the line had been present (in this case, all the way since revision 1.1). That knowledge can help you decide whether to look at the logs to find out the motivation for the change:

 
floss$ cvs log -r 1.21 hello.c 
RCS file: /usr/local/newrepos/myproj/hello.c,v 
Working file: hello.c 
head: 1.21 
branch: 
locks: strict 
access list: 
symbolic names: 
       random-tag: 1.20 
       start: 1.1.1.1 
       jrandom: 1.1.1 
keyword substitution: kv 
total revisions: 22;    selected revisions: 1 
description: 
---------------------------- 
revision 1.21 
date: 1999/07/25 20:17:42;  author: jrandom;  state: Exp;  lines: +1 -1 
say hello with renewed enthusiasm 
============================================================================
floss$  

-r の他に -D DATE オプションを使って注釈をフィルタリングすることがで きます:

 
floss$ cvs annotate -D "5 weeks ago" hello.c 
Annotations for hello.c 
*************** 
1.1          (jrandom  20-Jun-99): #include <stdio.h> 
1.1          (jrandom  20-Jun-99):  
1.1          (jrandom  20-Jun-99): void 
1.1          (jrandom  20-Jun-99): main () 
1.1          (jrandom  20-Jun-99): { 
1.1          (jrandom  20-Jun-99):   printf ("Hello, world!\n"); 
1.1          (jrandom  20-Jun-99): } 
floss$ cvs annotate -D "3 weeks ago" hello.c 
Annotations for hello.c 
*************** 
1.1          (jrandom  20-Jun-99): #include <stdio.h> 
1.1          (jrandom  20-Jun-99):  
1.1          (jrandom  20-Jun-99): void 
1.1          (jrandom  20-Jun-99): main () 
1.1          (jrandom  20-Jun-99): { 
1.1          (jrandom  20-Jun-99):   printf ("Hello, world!\n"); 
1.3          (jrandom  21-Jun-99):   printf ("hmmm\n"); 
1.4          (jrandom  21-Jun-99):   printf ("double hmmm\n"); 
1.2          (jrandom  21-Jun-99):   printf ("Goodbye, world!\n"); 
1.1          (jrandom  20-Jun-99): } 
floss$  



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.22 Annotations And Branches

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Annotations%20And%20Branches"
"j-cvsbook/A.22AnnotationsAndBranches"へのコメント(無し)
検索全文Elisp

デフォルトでは annotate は開発のメイントランクの動きを表示します。ブ ランチの作業コピーで起動した場合でも指定しない限りはトランクのほうを 表示します。(トランクに固執するのはバグか仕様か…それはあなたの見方 によります。) ブランチタグを -r で渡すとそのブランチの annotate を取 ることができます。以下の例は hello.c が Brancho_Gratuito とい う名前のブランチにある作業コピーからの例です。このブランチ上では少な くとも1つの変更がコミットされました:

 
floss$ cvs status hello.c 
=================================================================== 
File: hello.c           Status: Up-to-date 

  Working revision:    1.10.2.2        Sun Jul 25 21:29:05 1999 
  Repository revision: 1.10.2.2        /usr/local/newrepos/myproj/hello.c,v
  Sticky Tag:          Brancho_Gratuito (branch: 1.10.2) 
  Sticky Date:         (none) 
  Sticky Options:      (none) 

floss$ cvs annotate hello.c 
Annotations for hello.c 
*************** 
1.1          (jrandom  20-Jun-99): #include <stdio.h> 
1.1          (jrandom  20-Jun-99):  
1.1          (jrandom  20-Jun-99): void 
1.1          (jrandom  20-Jun-99): main () 
1.1          (jrandom  20-Jun-99): { 
1.10         (jrandom  12-Jul-99):   /* test */ 
1.1          (jrandom  20-Jun-99):   printf ("Hello, world!\n"); 
1.3          (jrandom  21-Jun-99):   printf ("hmmm\n"); 
1.4          (jrandom  21-Jun-99):   printf ("double hmmm\n"); 
1.2          (jrandom  21-Jun-99):   printf ("Goodbye, world!\n"); 
1.1          (jrandom  20-Jun-99): } 
floss$ cvs annotate -r Brancho_Gratuito hello.c 
Annotations for hello.c 
*************** 
1.1          (jrandom  20-Jun-99): #include <stdio.h> 
1.1          (jrandom  20-Jun-99):  
1.1          (jrandom  20-Jun-99): void 
1.1          (jrandom  20-Jun-99): main () 
1.1          (jrandom  20-Jun-99): { 
1.10         (jrandom  12-Jul-99):   /* test */ 
1.1          (jrandom  20-Jun-99):   printf ("Hello, world!\n"); 
1.10.2.2     (jrandom  25-Jul-99):   printf ("hmmmmm\n"); 
1.4          (jrandom  21-Jun-99):   printf ("double hmmm\n"); 
1.10.2.1     (jrandom  25-Jul-99):   printf ("added this line"); 
1.2          (jrandom  21-Jun-99):   printf ("Goodbye, world!\n"); 
1.1          (jrandom  20-Jun-99): } 
floss$  

ブランチ番号そのものを渡すこともできます:

 
floss$ cvs annotate -r 1.10.2 hello.c 
Annotations for hello.c 
*************** 
1.1          (jrandom  20-Jun-99): #include <stdio.h> 
1.1          (jrandom  20-Jun-99):  
1.1          (jrandom  20-Jun-99): void 
1.1          (jrandom  20-Jun-99): main () 
1.1          (jrandom  20-Jun-99): { 
1.10         (jrandom  12-Jul-99):   /* test */ 
1.1          (jrandom  20-Jun-99):   printf ("Hello, world!\n"); 
1.10.2.2     (jrandom  25-Jul-99):   printf ("hmmmmm\n"); 
1.4          (jrandom  21-Jun-99):   printf ("double hmmm\n"); 
1.10.2.1     (jrandom  25-Jul-99):   printf ("added this line"); 
1.2          (jrandom  21-Jun-99):   printf ("Goodbye, world!\n"); 
1.1          (jrandom  20-Jun-99): } 
floss$  

ブランチ上のリビジョン番号をフルに渡しても良いです:

 
floss$ cvs annotate -r 1.10.2.1 hello.c 
Annotations for hello.c 
*************** 
1.1          (jrandom  20-Jun-99): #include <stdio.h> 
1.1          (jrandom  20-Jun-99):  
1.1          (jrandom  20-Jun-99): void 
1.1          (jrandom  20-Jun-99): main () 
1.1          (jrandom  20-Jun-99): { 
1.10         (jrandom  12-Jul-99):   /* test */ 
1.1          (jrandom  20-Jun-99):   printf ("Hello, world!\n"); 
1.3          (jrandom  21-Jun-99):   printf ("hmmm\n"); 
1.4          (jrandom  21-Jun-99):   printf ("double hmmm\n"); 
1.10.2.1     (jrandom  25-Jul-99):   printf ("added this line"); 
1.2          (jrandom  21-Jun-99):   printf ("Goodbye, world!\n"); 
1.1          (jrandom  20-Jun-99): } 
floss$  

こうする場合には、そのリビジョン番号はそのファイルにだけ有効だという ことを忘れないようにして下さい。一般的にはできるだけブランチ名を使っ たほうが良いと思います。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.23 Using Keyword Expansion

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Using%20Keyword%20Expansion"
"j-cvsbook/A.23UsingKeywordExpansion"へのコメント(無し)
検索全文Elisp

An Overview of CVSkeyword expansion について少し書 いたことを思い出せると思います。RCS キーワードはドル記号でくくった特 殊な単語で、CVS はテキストファイル中にそれらがないか探し、リビジョン 管理情報に展開します。例えばファイルにこういう文字列があった場合

 
$Author$ 

そのファイルがあるリビジョンへアップデートされる時に、CVS はこれをそ のリビジョンをコミットした人のユーザ名に展開します:

 
$Author: jrandom $ 

CVS は展開後の形も認識しますので、展開された後も適切に更新されつづけ ます。

Although keywords don't actually offer any information that's not available by other means, they give people a convenient way to see revision control facts embedded in the text of the file itself, rather than by invoking some arcane CVS operation.

良く使われるほかのキーワードを紹介します:

 
$Date$       ==>  最終コミット日時。展開後 ==> 
$Date: 1999/07/26 06:39:46 $ 

$Id$         ==>  ファイル名、リビジョン、日時、著者。展開後 ==> 
$Id: hello.c,v 1.11 1999/07/26 06:39:46 jrandom Exp $ 

$Revision$   ==>  あなたの考えた通りです、展開後 ==> 
$Revision: 1.11 $ 

$Source$     ==> 対応するリポジトリファイルのパス。展開後 ==> 
$Source: /usr/local/newrepos/tossproj/hello.c,v $ 

$Log$        ==>  そのファイルへのログメッセージを蓄積。展開後 ==> 
$Log: hello.c,v $ 
Revision 1.2  1999/07/26 06:47:52  jrandom 
...and this is the second log message. 

Revision 1.1  1999/07/26 06:39:46  jrandom 
This is the first log message... 

$Log$ キーワードはこの中では唯一、展開後複数行にわたります。他のもの と違い、以前の展開結果が今回の展開結果で置き換えられるのではなく、最 新の展開結果に挿入されます。キーワードの直後に、空行1行とともに挿入 されます(従って、過去の展開結果は下へ押しやられていきます)。

さらに、行頭と $Log の間にある文字列は展開のプレフィクスになります (ログメッセージをプログラム内コメントにするために利用されます)。例え ばファイルにこう書くと

 
// $Log$ 

最初のコミットで次のように展開されるでしょう:

 
// $Log: hello.c,v $ 
// Revision 1.14  1999/07/26 07:03:20  jrandom 
// this is the first log message... 
// 

2度目のコミットではこうなります:

 
// $Log: hello.c,v $ 
// Revision 1.15  1999/07/26 07:04:40  jrandom 
// ...and this is the second log message... 
// 
// Revision 1.14  1999/07/26 07:03:20  jrandom 
// this is the first log message... 
// 

以降も同じように:

 
// $Log: hello.c,v $ 
// Revision 1.16  1999/07/26 07:05:34  jrandom 
// ...and this is the third!
// 
// Revision 1.15  1999/07/26 07:04:40  jrandom 
// ...and this is the second log message... 
// 
// Revision 1.14  1999/07/26 07:03:20  jrandom 
// this is the first log message... 
// 

いつもいつもログ履歴全部をファイルに保存したりしたくはないとお思いで しょう。その場合、長くなったらいつでも古いほうを削除して下さい。 cvs log を実行するよりも便利ですし、みんながログをコンスタントに読んでい なくてはいけないようなプロジェクトにおいても役に立つでしょう。

ファイル中に $Revision$ を持たせ、それをプログラムのバージョン番号と して使用するのは、良く使われるテクニックです。このやり方はプロジェク トが本質的に1つのファイルで構成されているか、または頻繁にリリースさ れていて、リリースごとの更新が保証されているファイルが少なくとも一つ ある場合にうまくいきます。プログラムのコード中に値として RCS キーワー ドを使うこともできます:

 
VERSION = "$Revision: 1.114 $"; 

CVS はキーワードを他の場合と同じようにただ展開します; プログラミング 言語での意味を考慮したりはしませんし、文字列がダブルクオートで保護さ れていると仮定したりもしません。

キーワードの完全な一覧(あまり知られていないようなのがあといくつかあ るんです)は CVS Reference に書いてあります。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.24 Going Out On A Limb (How To Work With Branches And Survive)

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Going%20Out%20On%20A%20Limb%20(How%20To%20Work%20With%20Branches%20And%20Survive)"
"j-cvsbook/A.24GoingOutOnALimb(HowToWorkWithBranchesAndSurvive)"へのコメント(無し)
検索全文Elisp

ブランチは CVS の最も重要な機能であると同時に、最も誤用されやすい機 能でもあります。危険または混乱するような変更を、その変更が安定するま で別の開発ラインに隔離しておけるのは便利です。しかしながら、ブランチ はきちんと管理しなければ、どの変更をいつマージしたかわからなくなり、 プロジェクトを容易に混乱に陥れることになります。

A.24.1 Some Principles For Working With Branches  
A.24.2 Merging Repeatedly Into The Trunk  
A.24.3 The Dovetail Approach -- Merging In And Out Of The Trunk  
A.24.4 The Flying Fish Approach -- A Simpler Way To Do It  
A.24.5 Branches And Keyword Expansion -- Natural Enemies  



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.24.1 Some Principles For Working With Branches

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Some%20Principles%20For%20Working%20With%20Branches"
"j-cvsbook/A.24.1SomePrinciplesForWorkingWithBranches"へのコメント(無し)
検索全文Elisp

ブランチを使った作業を成功させるためには、開発グループはこれらの原則 を守るべきでしょう:

これらの原則を心に留めつつ、典型的なブランチ開発シナリオを見ていくこ とにしましょう。jrandom がトランク上、qsmith がブランチ上に居ること にします。が、トランク及び/またはブランチ上には複数の開発者が居る可 能性があることに注意して下さい。各開発ライン上には通常何人いても構い ません。しかし、タグづけとマージは各ラインについて一人だけが実行する のがよいでしょう。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.24.2 Merging Repeatedly Into The Trunk

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Merging%20Repeatedly%20Into%20The%20Trunk"
"j-cvsbook/A.24.2MergingRepeatedlyIntoTheTrunk"へのコメント(無し)
検索全文Elisp

qsmith はトランクを jrandom と共有していて、それを不安定にさせたくな いのでしばらくブランチ上で開発をする必要があるとします。最初のステッ プはブランチの作成です。qsmith がまず通常の(ブランチでない)タグを作 成し、その後ブランチを作っていることに注意してください:

 
paste$ pwd 
/home/qsmith/myproj 
paste$ cvs tag Root-of-Exotic_Greetings 
cvs tag: Tagging . 
T README.txt 
T foo.gif 
T hello.c 
cvs tag: Tagging a-subdir 
T a-subdir/whatever.c 
cvs tag: Tagging a-subdir/subsubdir 
T a-subdir/subsubdir/fish.c 
cvs tag: Tagging b-subdir 
T b-subdir/random.c 
paste$ cvs tag -b Exotic_Greetings-branch 
cvs tag: Tagging . 
T README.txt 
T foo.gif 
T hello.c 
cvs tag: Tagging a-subdir 
T a-subdir/whatever.c 
cvs tag: Tagging a-subdir/subsubdir 
T a-subdir/subsubdir/fish.c 
cvs tag: Tagging b-subdir 
T b-subdir/random.c 
paste$  

最初トランクにタグづけした点は、将来、ブランチを作成した時点のトラン クにアクセスするときに必要になるでしょう。そういう必要がでてきた場合 に、ブランチ自体を参照することなくトランクのスナップショットを参照す ることができます。ブランチタグでは、ブランチの根のあるトランクではな く、ブランチにアクセスしてしまうので使えません。ブランチが生えている その同じリビジョンに、通常のタグを作るしか方法はありません。(「ブラ ンチの原則4、ブランチポイントにはノン-ブランチタグを作成する」とでも 言うべきこのルールを忠実に守っている人も居ますが、多くのサイトではこ れが守られていませんし、まあかまわないようにも思えます。趣味の問題で すね) これ以降ではこのようなノン-ブランチタグをブランチポイント タグと呼びます。

ブランチポイントタグは Root-of- で始まり、ハイフンではなくア ンダスコアで単語を区切った実際のブランチ名を続ける、という命名規則に も注意してください。実際のブランチを作成する時には、そのタグ名の最後 は -branch とします。タグ名を見ればそのタグがブランチタグだと わかるようにするためです。(ブランチポイントタグ Root-of-Exotic_Greetings には -branch とは書いてありません、 これはブランチタグではありませんので。) もちろん、この命名規則を使う 必要は特にありませんが、何らかの規則を用いるべきだと思います。

ああ、ちょっとうるさく言いすぎましたね。小さなプロジェクトでは、誰が 何をしているかをみんながが知っていて、混乱が起こっても容易に回復でき るので、このような規則を使わねばならないわけではありません。ブランチ ポイントタグを使うとかタグに厳しい命名規則を課すかどうかというのは、 プロジェクトの複雑度やブランチのやりかたによります。(あとでいつでも 戻って古いタグを新しい規則に沿うように直すことができることを忘れない でください。古いタグのバージョンにアクセスして、新しいタグをつけ、古 いタグを削除すればよいのです)

さて、qsmith はブランチで作業を開始します:

 
paste$ cvs update -r Exotic_Greetings-branch 
cvs update: Updating . 
cvs update: Updating a-subdir 
cvs update: Updating a-subdir/subsubdir 
cvs update: Updating b-subdir 
paste$  

ファイルをいくつか変更し、それをブランチへコミットします:

 
paste$ emacs README.txt a-subdir/whatever.c b-subdir/random.c 
... 
paste$ cvs ci -m "print greeting backwards, etc" 
cvs commit: Examining . 
cvs commit: Examining a-subdir 
cvs commit: Examining a-subdir/subsubdir 
cvs commit: Examining b-subdir 
Checking in README.txt; 
/usr/local/newrepos/myproj/README.txt,v  <--  README.txt 
new revision: 1.14.2.1; previous revision: 1.14 
done 
Checking in a-subdir/whatever.c; 
/usr/local/newrepos/myproj/a-subdir/whatever.c,v  <--  whatever.c 
new revision: 1.3.2.1; previous revision: 1.3 
done 
Checking in b-subdir/random.c; 
/usr/local/newrepos/myproj/b-subdir/random.c,v  <--  random.c 
new revision: 1.1.1.1.2.1; previous revision: 1.1.1.1 
done 
paste$  
<<<<<<< j-chapter-6.texi =======

この間、jrandom はトランクでの作業を続行しています。qsmith が触った 3つのファイルのうち2つを変更しました。 >>>>>>> 1.4

<<<<<<< j-chapter-6.texi Meanwhile, jrandom is continuing to work on the trunk. She modifies two of the three files that qsmith touched. Just for kicks, we'll have her make changes that conflict with qsmith's work:

======= 一方、 jrandom はトランク上で作業を続行しています。qsmith が触った3 つのファイルのうち、2つを変更しました。試しに、qsmith とコンフリクト するような変更を施してみましょう:

>>>>>>> 1.4
 
floss$ emacs README.txt whatever.c 
 ... 
floss$ cvs ci -m "some very stable changes indeed" 
cvs commit: Examining . 
cvs commit: Examining a-subdir 
cvs commit: Examining a-subdir/subsubdir 
cvs commit: Examining b-subdir 
Checking in README.txt; 
/usr/local/newrepos/myproj/README.txt,v  <--  README.txt 
new revision: 1.15; previous revision: 1.14 
done 
Checking in a-subdir/whatever.c; 
/usr/local/newrepos/myproj/a-subdir/whatever.c,v  <--  whatever.c 
new revision: 1.4; previous revision: 1.3 
done 
floss$  

コンフリクトがあるようには見えません。当たり前ですね、ブランチとトラン クをマージしようとしたわけではありませんから。ではここで jrandom が マージを実行します:

 
floss$ cvs update -j Exotic_Greetings-branch 
cvs update: Updating . 
RCS file: /usr/local/newrepos/myproj/README.txt,v 
retrieving revision 1.14 
retrieving revision 1.14.2.1 
Merging differences between 1.14 and 1.14.2.1 into README.txt 
rcsmerge: warning: conflicts during merge 
cvs update: Updating a-subdir 
RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v 
retrieving revision 1.3 
retrieving revision 1.3.2.1 
Merging differences between 1.3 and 1.3.2.1 into whatever.c 
rcsmerge: warning: conflicts during merge 
cvs update: Updating a-subdir/subsubdir 
cvs update: Updating b-subdir 
RCS file: /usr/local/newrepos/myproj/b-subdir/random.c,v 
retrieving revision 1.1.1.1 
retrieving revision 1.1.1.1.2.1 
Merging differences between 1.1.1.1 and 1.1.1.1.2.1 into random.c 
floss$ cvs update 
cvs update: Updating . 
C README.txt 
cvs update: Updating a-subdir 
C a-subdir/whatever.c 
cvs update: Updating a-subdir/subsubdir 
cvs update: Updating b-subdir 
M b-subdir/random.c 
floss$  

ファイルが2つ、コンフリクトを起こしました。たいした問題ではありません、 jrandom はいつものように機転を利かせてコンフリクトを解消し、コミット した後、トランクにマージ成功のタグをつけます:

 
floss$ emacs README.txt a-subdir/whatever.c 
 ... 
floss$ cvs ci -m "merged from Exotic_Greetings-branch (conflicts resolved)"
cvs commit: Examining . 
cvs commit: Examining a-subdir 
cvs commit: Examining a-subdir/subsubdir 
cvs commit: Examining b-subdir 
Checking in README.txt; 
/usr/local/newrepos/myproj/README.txt,v  <--  README.txt 
new revision: 1.16; previous revision: 1.15 
done 
Checking in a-subdir/whatever.c; 
/usr/local/newrepos/myproj/a-subdir/whatever.c,v  <--  whatever.c 
new revision: 1.5; previous revision: 1.4 
done 
Checking in b-subdir/random.c; 
/usr/local/newrepos/myproj/b-subdir/random.c,v  <--  random.c 
new revision: 1.2; previous revision: 1.1 
done 
floss$ cvs tag merged-Exotic_Greetings 
cvs tag: Tagging . 
T README.txt 
T foo.gif 
T hello.c 
cvs tag: Tagging a-subdir 
T a-subdir/whatever.c 
cvs tag: Tagging a-subdir/subsubdir 
T a-subdir/subsubdir/fish.c 
cvs tag: Tagging b-subdir 
T b-subdir/random.c 
floss$  

qsmith は開発を続行するのにマージが終わるのを待つ必要はありません。 qsmith は jrandom がマージした後の一連の変更に対し、タグをつけておけ ばよいのです。(あとで jrandom はこのタグ名を知る必要があります; 一般 に、ブランチというものは開発者が頻繁かつ綿密に連絡を取り合って初めて 成り立つものなのです):

 
paste$ cvs tag Exotic_Greetings-1 
cvs tag: Tagging . 
T README.txt 
T foo.gif 
T hello.c 
cvs tag: Tagging a-subdir 
T a-subdir/whatever.c 
cvs tag: Tagging a-subdir/subsubdir 
T a-subdir/subsubdir/fish.c 
cvs tag: Tagging b-subdir 
T b-subdir/random.c 
paste$ emacs a-subdir/whatever.c 
 ... 
paste$ cvs ci -m "print a randomly capitalized greeting" 
cvs commit: Examining . 
cvs commit: Examining a-subdir 
cvs commit: Examining a-subdir/subsubdir 
cvs commit: Examining b-subdir 
Checking in a-subdir/whatever.c; 
/usr/local/newrepos/myproj/a-subdir/whatever.c,v  <--  whatever.c 
new revision: 1.3.2.2; previous revision: 1.3.2.1 
done 
paste$  

もちろん、qsmith は変更が終わり次第タグをつけるべきです:

 
paste$ cvs -q tag Exotic_Greetings-2 
T README.txt 
T foo.gif 
T hello.c 
T a-subdir/whatever.c 
T a-subdir/subsubdir/fish.c 
T b-subdir/random.c 
paste$  

これをやっている間、qsmith が一連の編集で触ったのとは別のファイルを jrandom が変更したとします:

 
floss$ emacs README.txt 
 ... 
floss$ cvs ci -m "Mention new Exotic Greeting features" README.txt 
Checking in README.txt; 
/usr/local/newrepos/myproj/README.txt,v  <--  README.txt 
new revision: 1.17; previous revision: 1.16 
done 
floss$  

ここで qsmith は新たな変更をブランチにコミットし、jrandom は別のファ イルのコンフリクトしない変更をトランクにコミットします。jrandom がブ ランチをもう一度マージしようとしたときに何が起こるか見てみましょう:

 
floss$ cvs -q update -j Exotic_Greetings-branch 
RCS file: /usr/local/newrepos/myproj/README.txt,v 
retrieving revision 1.14 
retrieving revision 1.14.2.1 
Merging differences between 1.14 and 1.14.2.1 into README.txt 
rcsmerge: warning: conflicts during merge 
RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v 
retrieving revision 1.3 
retrieving revision 1.3.2.2 
Merging differences between 1.3 and 1.3.2.2 into whatever.c 
rcsmerge: warning: conflicts during merge 
RCS file: /usr/local/newrepos/myproj/b-subdir/random.c,v 
retrieving revision 1.1 
retrieving revision 1.1.1.1.2.1 
Merging differences between 1.1 and 1.1.1.1.2.1 into random.c 
floss$ cvs -q update 
C README.txt 
C a-subdir/whatever.c 
floss$  

コンフリクトが起きてしまいました! これ、予測していましたか?

マージの意味に問題があるようです。先に An Overview of CVS で述 べた通り、作業コピー中で

 
floss$ cvs update -j BRANCH 

を実行すると、CVS はブランチの根と先端の相違を作業コピーにマージする のです。今回の場合、それらの変更の大半は、jrandom が最初に行ったマー ジの時に既にトランクに組み込まれているので、この動作は問題になります。 CVS がその変更を再びマージしようとすると(その変更自身に上書きするよ うなことになります)、当然コンフリクトだと見なされるわけです。

jrandom が本当にやりたかったことは、ブランチのうち、一番最後に実行し たマージ時点と現在のブランチ先端の間の変更を作業コピーにマージする、 ということだったのです。これをするには update に -j フラグを2つ渡せ ばよいのです。An Overview of CVS を思い出して下さい。これをす るには、各フラグでどのリビジョンを指定すれば良いかを知っておかなけれ ばなりません。幸い、qsmith は最後のマージポイントにタグをつけておき ましたので(hurrah for planning ahead!)、これについて問題はありません。 まずは jrandom の作業コピーを元のきれいな状態に戻しましょう。そこか ら再マージするのです:

 
floss$ rm README.txt a-subdir/whatever.c 
floss$ cvs -q update 
cvs update: warning: README.txt was lost 
U README.txt 
cvs update: warning: a-subdir/whatever.c was lost 
U a-subdir/whatever.c 
floss$  

さて、これでマージの準備ができました、今回は qsmith がつけてくれたタ グを使うことにしましょう:

 
floss$ cvs -q update -j Exotic_Greetings-1 -j Exotic_Greetings-branch 
RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v 
retrieving revision 1.3.2.1 
retrieving revision 1.3.2.2 
Merging differences between 1.3.2.1 and 1.3.2.2 into whatever.c 
floss$ cvs -q update 
M a-subdir/whatever.c 
floss$  

いいカンジです。qsmith の変更が whatever.c に組み込まれました; jrandom はコミットし、タグをつけます:

 
floss$ cvs -q ci -m "merged again from Exotic_Greetings (1)"
Checking in a-subdir/whatever.c; 
/usr/local/newrepos/myproj/a-subdir/whatever.c,v  <--  whatever.c 
new revision: 1.6; previous revision: 1.5 
done 
floss$ cvs -q tag merged-Exotic_Greetings-1 
T README.txt 
T foo.gif 
T hello.c 
T a-subdir/whatever.c 
T a-subdir/subsubdir/fish.c 
T b-subdir/random.c 
floss$  

qsmith がマージポイントにタグをつけるのを忘れても、望みがなくなって しまったわけではありません。 jrandom が qsmith の最初の変更を大体い つ頃コミットしたか覚えていれば、日付でフィルタリングしてみることがで きます:

 
floss$ cvs update -j Exotic_Greetings-branch:3pm -j Exotic_Greetings_branch 

日付でフィルタリングするのは、最後の切り札にはなりますが、あまり理想 的な方法とは言えません。なぜなら、信頼に足る開発上の名称ではなく、人 の記憶に頼った方法だからです。qsmith の初回マージ分の変更が、1回のコ ミットではなく何度かに分けてコミットされていた場合、jrandom が間違っ て日付や時刻を指定すると、変更全てではなく一部分だけを取ってきてしま う可能性があります。

qsmith の変更のタグづけできる各ポイントが、1回のコミットでリポジトリ に送られなければならない理由はありません。この例でたまたまこうなって いるだけなのです。実際には、qsmith はタグとタグの間に何度かコミット するかもしれません。qsmith はブランチ上でひとりで作業したければ、そ うすることができます。タグというのはつまり、トランクへマージできると 思う点をブランチ上に連続的に記録していくことなのです。jrandom が常に -j フラグを2つ使ってマージし、qsmith のマージタグを正しい順序で注意深 く用いてそれぞれを1度だけ使う限り、トランクでダブルマージの問題が起 こることはないでしょう。コンフリクトは起こるかもしれませんが、それは 人の手で解決しなければならない、不可避なものなのでしょう。同じ領域に おいて、ブランチでもトランクでも変更があるような状況だというわけです。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.24.3 The Dovetail Approach -- Merging In And Out Of The Trunk

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=The%20Dovetail%20Approach%20--%20Merging%20In%20And%20Out%20Of%20The%20Trunk"
"j-cvsbook/A.24.3TheDovetailApproach--MergingInAndOutOfTheTrunk"へのコメント(無し)
検索全文Elisp

ブランチからトランクへ何度もマージするというのは、トランク上に居る人々 にとっては良いことです。なぜなら、自分たちの変更も、ブランチからの変 更も全てわかるからです。しかしながら、ブランチ上の開発者はトランク上 での作業分を組み込めないのです。

これをするためには、ブランチ開発者は時々余分なステップを踏む必要があ ります。(最新のトランクの変更をマージしたいと思ったり、避けられない コンフリクトをどうにかしたいと思った時はいつでも、という意味です):

 
paste$ cvs update -j HEAD 

特別に予約されたタグ HEAD は、トランクの先端を意味しています。こ のコマンドは、現在のブランチの根(Exotic_Greetings-branch)から、ト ランク上の現在の最大のリビジョンまでの変更をすべてマージします。もちろん、 qsmithはこれを実行したあと再度タグをつけなければなりません。トランク上の 開発者が qsmith の変更をマージしようとしたときに、誤って自分自身の変更を マージしてしまうことを避けられるようにするためです。

ブランチ開発者も同様に、最後にマージしてから現在状態までのトランクの変更 を正確にブランチにマージするために、トランクのマージタグを境界として使用 することができます(トランクがマージするのと同じ方法で)。例えば、jrandom がブランチからマージした後 hello.c に変更を施したとします:

 
floss$ emacs hello.c 
 ... 
floss$ cvs ci -m "clarify algorithm" hello.c 
Checking in hello.c; 
/usr/local/newrepos/myproj/hello.c,v  <--  hello.c 
new revision: 1.22; previous revision: 1.21 
done 
floss$  

その後、qsmith がこれらの変更をブランチにマージし、コミットし、タグをつ けます:

 
paste$ cvs -q update -j merged-Exotic_Greetings-1 -j HEAD 
RCS file: /usr/local/newrepos/myproj/hello.c,v 
retrieving revision 1.21 
retrieving revision 1.22 
Merging differences between 1.21 and 1.22 into hello.c 
paste$ cvs -q update 
M hello.c 
paste$ cvs -q ci -m "merged trunk, from merged-Exotic_Greetings-1 to HEAD" 
Checking in hello.c; 
/usr/local/newrepos/myproj/hello.c,v  <--  hello.c 
new revision: 1.21.2.1; previous revision: 1.21 
done 
paste$ cvs -q tag merged-merged-Exotic_Greetings-1 
T README.txt 
T foo.gif 
T hello.c 
T a-subdir/whatever.c 
T a-subdir/subsubdir/fish.c 
T b-subdir/random.c 
paste$  

jrandom は hello.c の変更をコミットした後にタグづけせず、qsmith がそれを したということに注意してください。ここでの原則では、ちょっとした変更のあ とにいちいちタグをつける必要はなくて、マージの後、及び自分の開発ラインの マージできる状態をコミットした後に常にタグをつけるべきなのです。こうすれ ば、他の人(別のブランチにいるのでしょう)に自分自身のマージの基礎となる参 照の点がわかります。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.24.4 The Flying Fish Approach -- A Simpler Way To Do It

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=The%20Flying%20Fish%20Approach%20--%20A%20Simpler%20Way%20To%20Do%20It"
"j-cvsbook/A.24.4TheFlyingFishApproach--ASimplerWayToDoIt"へのコメント(無し)
検索全文Elisp

albeit slightly limiting ちょっと制限してはいますが

前述のものよりも少々制限はありますが、より簡単な方法があります。ブラン チ開発者はトランクがマージしている間開発を停止し、トランク開発者は今 までのブランチを置き換えるような全く新しいブランチを作成します。ブラン チ開発者はその新しいブランチに移り、開発を続けます。そのサイクルはブ ランチ開発が必要なくなるまで続きます。こんな感じになります(要約です。 今まで通り、jrandom@floss がトランクに、 qsmith@paste がブランチに 居ることにします):

 
floss$ cvs tag -b BRANCH-1 
paste$ cvs checkout -r BRANCH-1 myproj 

トランク、ブランチともに作業を始めます。そして開発者たちは協議し、ブ ランチをトランクにマージする時であると決定します:

 
paste$ cvs ci -m "committing all uncommitted changes" 
floss$ cvs update -j BRANCH-1 

ブランチでの変更が全てマージされます: ブランチ開発者はトランク開発者 がコンフリクトを解消し、コミットしてタグをつけ、新しいブランチを作成 するまで作業を停止します:

 
floss$ cvs ci -m "merged from BRANCH-1" 
floss$ cvs tag merged-from-BRANCH-1 
floss$ cvs tag -b BRANCH-2 

ここでブランチ開発者は自分の作業コピーを新しいブランチで上書きします; マージが起こった時には最新で、新しいブランチは古いブランチの変更が組 み込まれたトランクからのものですから、そうしても未コミットの変更を失っ たりしないのです。

 
paste$ cvs update -r BRANCH-2 

BRANCH-1 を BRANCH-2 に、BRANCH-2 を BRANCH-3 に置き換えて、 限りなくこのサイクルは続いていきます。

筆者はこれを トビウオ テクニックと呼んでいます。ブランチがたえ ずトランクから生え、短く伸びてはまたトランクへ再接合するからです。こ のやりかたの利点は、シンプルであること(トランクは常に指定されたブラン チの全ての変更をマージする)、それとブランチ開発者はコンフリクトを解 消しなくてもいいということです(新しくてきれいなブランチをただ渡され て、その上で作業すればいいのです)。欠点は当然、トランクのマージを実 施している間、ブランチ開発者はただ座ってボケっとしていなければならな いということです(解決すべきコンフリクトがいくつあるかによって、それ なりの時間がかかるでしょう)。あまり重要ではないですが、もうひとつ欠 点があります。それは、使われないノンブランチタグの代わりに、使われて いない小さなブランチがたくさんできることです。しかし、小さくて使われ ていないブランチがたくさんあっても気にならなくて、トラブルのないマー ジを期待しているのなら、トビウオは一番簡単なやり方になるでしょう。心 に留めておいてもいいと思います。

どちらのやり方を取るにしろ、分離状態は出来るだけ短い間にするよう努力 したほうが良いでしょう。ブランチとトランクをずっとマージしないままに すると、ただのテキストのズレだけでは済まず、意味上のズレに悩まされる ことになります。テキスト上のコンフリクトを起こす変更は簡単に解消でき ますが、テキストではなく考え方においてコンフリクトを起こすような変更 は、見つけるのも解決するのも大変です。ブランチを隔離するというのは、 開発者を自由にしますが、他の人の変更からしばらくの間でも遮蔽されると いうのは危険なことです。ブランチを使う場合は普段よりも活発にコミュニ ケーションをとるようになります。全員がお互いの計画を検討し、同じ軌道 に乗っているかどうか確認する必要があります。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.24.5 Branches And Keyword Expansion -- Natural Enemies

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Branches%20And%20Keyword%20Expansion%20--%20Natural%20Enemies"
"j-cvsbook/A.24.5BranchesAndKeywordExpansion--NaturalEnemies"へのコメント(無し)
検索全文Elisp

ファイルに RCS キーワードがあると、ブランチ上とトランク上では違った ように展開されるので、マージするたびににせのコンフリクトが起こること になります。何も変更していなくてもキーワードはオーバラップし、展開結 果は一致しません。例えば README.txt に、トランクではこのように書いて あるとします

 
$Revision: 1.14 $ 

ブランチ上ではこうです

 
$Revision: 1.14.2.1 $ 

マージを実行した時に、以下のようなコンフリクトが起こるでしょう:

 
floss$ cvs update -j Exotic_Greetings-branch
RCS file: /usr/local/newrepos/myproj/README.txt,v
retrieving revision 1.14
retrieving revision 1.14.2.1
Merging differences between 1.14 and 1.14.2.1 into README.txt
rcsmerge: warning: conflicts during merge
floss$ cat README.txt
 ... 
<<<<<<< README.txt 
key $Revision: 1.14 $ 
======= 
key $Revision: 1.14.2.1 $ 
>>>>>>> 1.14.2.1 
 ... 
floss$  

こうならないようにするために、マージ時に一時的に -kk オプション(何の 略なのか知らないんですが、多分 "kill keywords" かな?)を渡して展開を 抑制することができます:

 
floss$ cvs update -kk -j Exotic_Greetings-branch 
RCS file: /usr/local/newrepos/myproj/README.txt,v 
retrieving revision 1.14 
retrieving revision 1.14.2.1 
Merging differences between 1.14 and 1.14.2.1 into README.txt 
floss$ cat README.txt 
 ... 
$Revision$ 
 ... 
floss$  

しかし、気をつけることがひとつだけあります: -kk を使うと、そのファイ ルに設定してあるほかのキーワード展開モードを上書きしてしまいます。特 にバイナリファイルにおいては問題になります。バイナリファイルは普通 -kb になっているからです(-kb はキーワード展開と行末コード変換を全て 抑制します)。ブランチからバイナリファイルをマージする時には -kk を使 わないようにして、コンフリクトは手で直して下さい。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.25 Tracking Third-Party Sources (Vendor Branches)

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Tracking%20Third-Party%20Sources%20(Vendor%20Branches)"
"j-cvsbook/A.25TrackingThird-PartySources(VendorBranches)"へのコメント(無し)
検索全文Elisp

外部の配布元から取ってきたソフトウェアに、あるサイトでローカルな変更 が加えられることがあります。そのローカルな変更を配布元が受け入れない 場合(そうできないについて正当な理由はいくらでも考えられます)、そのサ イトはそのソフトウェアのアップグレードを受け取るたびにその変更をメン テせねばなりません。

CVS の ベンダブランチ(vendor branches) という機能がこの仕事に 役立ちます。ベンダブランチというのは cvs import のわけのわからない最 後の2つの引数の説明でした(今まではね)。An Overview of CVS でこ じつけたベンダタグとリリースタグのことです。

ここで、それがどのように動くか示します。最初のインポートは他の CVS プロジェクトの最初のインポートと同様です(ちょっと注意してベンダタグ とリリースタグを決めないといけませんが):

 
floss$ pwd 
/home/jrandom/theirproj-1.0 
floss$ cvs import -m "Import of TheirProj 1.0" theirproj Them THEIRPROJ_1_0
N theirproj/INSTALL 
N theirproj/README 
N theirproj/src/main.c 
N theirproj/src/parse.c 
N theirproj/src/digest.c 
N theirproj/doc/random.c 
N theirproj/doc/manual.txt 

No conflicts created by this import 

floss$  

そしてどこかに作業コピーをチェックアウトして、ローカルな変更を施し、 その後コミットして下さい:

 
floss$ cvs -q co theirproj 
U theirproj/INSTALL 
U theirproj/README 
U theirproj/doc/manual.txt 
U theirproj/doc/random.c 
U theirproj/src/digest.c 
U theirproj/src/main.c 
U theirproj/src/parse.c 
floss$ cd theirproj 
floss$ emacs src/main.c src/digest.c 
 ... 
floss$ cvs -q update 
M src/digest.c 
M src/main.c 
floss$ cvs -q ci -m "changed digestion algorithm; added comment to main" 
Checking in src/digest.c; 
/usr/local/newrepos/theirproj/src/digest.c,v  <--  digest.c 
new revision: 1.2; previous revision: 1.1 
done 
Checking in src/main.c; 
/usr/local/newrepos/theirproj/src/main.c,v  <--  main.c 
new revision: 1.2; previous revision: 1.1 
done 
floss$  

1年後、そのソフトウェアの次のバージョンが Them, Inc. から届きます。 ローカルの変更をそのバージョンにも取り入れなければなりません。配布元 での変更とローカルの変更は、少しだけ重なっているところがあります。配 布元では新しいファイルを一つ追加し、あなたの触ってないファイル2つを 変更し、あなたが触ったファイル2つにも変更を加えています。

まずやることは、もう1度インポートすることです。今回は新しいソースか らインポートします。初回インポートとほとんど同じです。リポジトリ中、 以前と同じプロジェクトの、同じベンダブランチにインポートします。違う のはリリースタグだけです:

 
floss$ pwd 
/home/jrandom/theirproj-2.0 
floss$ cvs -q import -m "Import of TheirProj 2.0" theirproj Them THEIRPROJ_2_0
U theirproj/INSTALL 
N theirproj/TODO 
U theirproj/README 
cvs import: Importing /usr/local/newrepos/theirproj/src 
C theirproj/src/main.c 
U theirproj/src/parse.c 
C theirproj/src/digest.c 
cvs import: Importing /usr/local/newrepos/theirproj/doc 
U theirproj/doc/random.c 
U theirproj/doc/manual.txt 

2 conflicts created by this import. 
Use the following command to help the merge: 

       cvs checkout -jThem:yesterday -jThem theirproj 

floss$  

おやまあ、CVS がこんな風に助けようとしてくれたのは今まで見たことがあ りませんね。変更をマージするためにどんなコマンドを実行するか教えてく れています。それに、ほとんど正しいですよ! 実際、示されたコマンドは動 きますが(yesterday のところを、最初のインポートを含んでいるが2番目の インポートを含んでいない時間間隔に調整したとして)、著者は代わりにリ リースタグを使うほうが好きです:

 
floss$ cvs checkout -j THEIRPROJ_1_0 -j THEIRPROJ_2_0 theirproj 
cvs checkout: Updating theirproj 
U theirproj/INSTALL 
U theirproj/README 
U theirproj/TODO 
cvs checkout: Updating theirproj/doc 
U theirproj/doc/manual.txt 
U theirproj/doc/random.c 
cvs checkout: Updating theirproj/src 
U theirproj/src/digest.c 
RCS file: /usr/local/newrepos/theirproj/src/digest.c,v 
retrieving revision 1.1.1.1 
retrieving revision 1.1.1.2 
Merging differences between 1.1.1.1 and 1.1.1.2 into digest.c 
rcsmerge: warning: conflicts during merge 
U theirproj/src/main.c 
RCS file: /usr/local/newrepos/theirproj/src/main.c,v 
retrieving revision 1.1.1.1 
retrieving revision 1.1.1.2 
Merging differences between 1.1.1.1 and 1.1.1.2 into main.c 
U theirproj/src/parse.c 
floss$  

インポートでコンフリクトが2つあるというふうに表示されたのに、マージ ではコンフリクトが1つしかないことに注意して下さい。インポートとその 他ではコンフリクトが少し違うものだと CVS が思っているように見えます。 インポートでは基本的に、前回のインポートと今回のインポートの間に、あ なたとベンダ両方が変更したファイルをコンフリクトとして報告します。し かしマージの時点になると、「コンフリクト」の通常の定義に忠実なのです。 つまり、変更が重なっている、という意味になります。重なり合っていない 変更は通常の方法でマージされ、そのファイルはただの変更として示されま す。

ちょっと diff を取ってみると、ファイルのうち1つだけにコンフリクトマー カがあることがわかります:

 
floss$ cvs -q update 
C src/digest.c 
M src/main.c 
floss$ cvs diff -c 
Index: src/digest.c 
===================================================================
RCS file: /usr/local/newrepos/theirproj/src/digest.c,v 
retrieving revision 1.2 
diff -c -r1.2 digest.c 
*** src/digest.c        1999/07/26 08:02:18     1.2 
-- src/digest.c        1999/07/26 08:16:15 
*************** 
*** 3,7 **** 
-- 3,11 ---- 
 void 
 digest () 
 { 
+ <<<<<<< digest.c 
   printf ("gurgle, slorp\n"); 
+ ======= 
+   printf ("mild gurgle\n"); 
+ >>>>>>> 1.1.1.2 
 } 
Index: src/main.c 
=================================================================== 
RCS file: /usr/local/newrepos/theirproj/src/main.c,v 
retrieving revision 1.2 
diff -c -r1.2 main.c 
*** src/main.c  1999/07/26 08:02:18     1.2 
-- src/main.c  1999/07/26 08:16:15 
*************** 
*** 7,9 **** 
-- 7,11 ---- 
 { 
   printf ("Goodbye, world!\n"); 
 } 
+  
+ /* I, the vendor, added this comment for no good reason. */ 
floss$  

こうなると他のマージと同じように、ただコンフリクトを解消すればいいだ けの話になります:

 
floss$ emacs  src/digest.c  src/main.c 
 ... 
floss$ cvs -q update 
M src/digest.c 
M src/main.c 
floss$ cvs diff src/digest.c 
cvs diff src/digest.c  
Index: src/digest.c 
=================================================================== 
RCS file: /usr/local/newrepos/theirproj/src/digest.c,v 
retrieving revision 1.2 
diff -r1.2 digest.c 
6c6 
<   printf ("gurgle, slorp\n"); 
-- 
>   printf ("mild gurgle, slorp\n"); 
floss$  

そして変更をコミットします

 
floss$ cvs -q ci -m "Resolved conflicts with import of 2.0" 
Checking in src/digest.c; 
/usr/local/newrepos/theirproj/src/digest.c,v  <--  digest.c 
new revision: 1.3; previous revision: 1.2 
done 
Checking in src/main.c; 
/usr/local/newrepos/theirproj/src/main.c,v  <--  main.c 
new revision: 1.3; previous revision: 1.2 
done 
floss$  

あとはベンダからの次のリリースを待つだけです。(もちろん、ローカルの 変更がちゃんと動くかどうかテストしたいだろうと思いますけれど!)

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



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.26 Exporting For Public Distribution

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=Exporting%20For%20Public%20Distribution"
"j-cvsbook/A.26ExportingForPublicDistribution"へのコメント(無し)
検索全文Elisp

CVS は開発者にとっては良い配布機構なのですが、大部分のユーザがソフト ウェアを取ってくる時にはダウンロードできるパッケージを取ってくると思 います。このパッケージは一般には CVS の作業コピーではなくただのソー スツリーで、ユーザのシステムに合わせて簡単にコンフィギュレーション・ コンパイルができるようになっているものです。

しかし、CVS はパッケージを作るのに便利な機構を提供しています。 cvs export コマンドです。プロジェクトをエクスポート するというのは、プロジェクトの作業コピーをチェックアウトするのと同じ ようなものですが、CVS 管理サブディレクトリを抜きにして プロジェクトツリーをチェックアウトするというところが違います。これは つまり、作業コピーではなくソースツリーだけを取得したということになり ます。そのソースツリーはどこから来たものなのか、それらのファイルがど の CVS バージョンなのかわかりません。つまり、エクスポートされたコピー はダウンロードしてディストリビューションをほどいたときの状態と同じな のです。そのプロジェクトが作業コピーから直接コンパイルできるようになっ ているとすると(そしてそうなっているべきなのです!)、エクスポートされ たコピーもコンパイルできるはずです。

export コマンドは checkout と同じように動作しますが、 タグ名か日付を指定しなければいけないというところが違います。プロジェ クトにリリース名でタグをつけて、それに基づいてエクスポートしてみましょ う:

 
floss$ pwd
/home/jrandom/myproj
floss$ cvs -q tag R_1_0
T README.txt
T hello.c
T a-subdir/whatever.c
T a-subdir/subsubdir/fish.c
T b-subdir/random.c
floss$ cd ..
floss$ cvs -d /usr/local/newrepos -q export -r R_1_0 -d myproj-1.0 myproj
U myproj-1.0/README.txt
U myproj-1.0/hello.c
U myproj-1.0/a-subdir/whatever.c
U myproj-1.0/a-subdir/subsubdir/fish.c
U myproj-1.0/b-subdir/random.c
floss$ cd myproj-1.0
floss$ ls
README.txt  a-subdir  b-subdir  hello.c

export コマンドは作業コピーの中ではないところで起動されるので、 どのリポジトリを使うかを -d グローバルオプションで指定してや らなければならないことに注意して下さい。またこの例では、ディレクトリ 名をデフォルトのプロジェクト名ではなく、明示的に指定して (myproj-1.0)エクスポートしています。その名前で作業コピーが既 に存在しているからです。この状況は珍しいことではないと思います。

上の例のようにエクスポートコピーが作成されたあとは、プロジェクトが単 純なものの場合、次のようにすればリリースが完了します:

 
floss$ tar cf myproj-1.0.tar myproj-1.0
floss$ gzip --best myproj-1.0.tar
floss$ ls
myproj/   myproj-1.0/   myproj-1.0.tar.gz
floss$ rm -rf myproj-1.0
floss$ mv myproj-1.0.tar.gz /home/ftp/pub/myproj/

もちろん、これらのコマンドを全部手で走らせたりすることはめったにあり ません。cvs export はリリースやパッケージの処理をするスク リプトから呼ばれることが多いでしょう。公のリリースに先立っていくつか の「テスト」リリースをするような場合は、リリースパッケージを作成する 処理は高度に自動化されていることが望ましいと思います。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

A.27 The Humble Guru

URL="http://www.bookshelf.jp/cgi-bin/goto.cgi?file=j-cvsbook&node=The%20Humble%20Guru"
"j-cvsbook/A.27TheHumbleGuru"へのコメント(無し)
検索全文Elisp

この章を全て読んで理解したら(そして実際やってみるとなお良い)、CVS に ついてとても驚くようなことはもうなにも残っていないと自信を持ってよい でしょう。少なくとも、誰かが新しい機能を CVS に追加するまでは。CVS を大きなプロジェクトで使うために知る必要のあることはすべて述べました。

うぬぼれる前に、4章で言ったことを繰り返しますが info-cvs@gnu.org メーリングリストを購読することをお勧めし ます。インターネットのメーリングリストの大部分は S/N 比が低下している にもかかわらず、届く情報のほとんどは待つに値するものです。筆者がこの 章を書いている間ずっと購読していたのですが(実はそれより前の章でもそ うだったんですが)、CVS の動作の細部の重要なところについて、他の人の 投稿から学んだことがどんなにたくさんあるか知ったら、きっと驚くと思い ます。CVS を本気で使う気があるのなら、また、開発者グループの CVS 管 理者の人は特に、他の真面目なユーザの人たちと知識を共有することによっ て恩恵をたくさん受けることが出来ると思います。


[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端] [?]