ノード:Getting Snapshots (Dates And Tagging), 次:, 前:Avoiding Option Fatigue, 上:Other Useful CVS Commands



Getting Snapshots (Dates And Tagging)

バグレポートが舞い込んできて壊れた状態になったプログラムの話に戻りましょ う。開発者は突然、最後のリリースの時点のプロジェクト全体にアクセスしなく てはなりません。ファイルはあれもこれも変更してあって、おまけにリビジョン 番号がファイルによってバラバラであろうとも、です。ログメッセージを見て、 ファイルごとにリリースのときのリビジョン番号はどれだったか探して、それぞ れ -r でリビジョン番号指定して update 走らせて、なんて、考えただけで時間 食いそうです。中規模から大規模のプロジェクト(数十から数百のファイルがあ るような…)でそんなことをして、ふりまわされたくないでしょう。

そこで CVS はプロジェクト中の過去のリビジョンをひとまとめにアクセスでき る方法を提供しています。実際には2つの方法が用意されています。ひとつは日 付指定で、コミットされた時刻をもとにリビジョンを選択する方法。もうひとつ はタグ指定で、過去にプロジェクトのスナップショットとしてマークをつけたも のにアクセスする方法。

状況によってどちらを選択するかが決まってきます。日付指定アクセスは update に -D フラグを渡すことによって実行できます。-r に似ていますがリビ ジョン番号のかわりに日付を指定します:

floss$ cvs -q update -D "1999-04-19"
U hello.c
U a-subdir/subsubdir/fish.c
U b-subdir/random.c
floss$

-D オプションを指定すると、update は指定された日付のなかで一番大きいリビ ジョンのファイルを取ってきて、必要があれば作業コピー中のファイルをそのリ ビジョンで置き換えます。

日付だけでなく、時刻も指定できます(したほうがいいことも多いです)。たとえ ば上のコマンドでは全部リビジョン1.1を取ってきています(表示された3つのファ イルだけが変更されていますが、それは他のファイルが全て1.1のままだからで す)。hello.c のステータスを見て確認しましょう:

floss$ cvs -Q status hello.c
===================================================================
File: hello.c                 Status: Up-to-date
   Working revision:          1.1.1.1 Sat Apr 24 22:45:03 1999
   Repository revision:       1.1.1.1 /usr/local/cvs/myproj/hello.c,v
   Sticky Date:               99.04.19.05.00.00
floss$

でもこの章の最初のほうにちょっと戻ってログメッセージを見てみると、 hello.c のリビジョン1.2は確かに1999/4/19にコミットされているはずなのに。 どうしてリビジョン1.2ではなく1.1を取ってきたのでしょう?

これは、"1999-04-19" という日付が「1999-04-19が始まる真夜中」、つま りその日の最初の瞬間、という意味に解釈されてしまうことが問題なのです。こ れはたぶん、望んだことではないですね。1.2 はその日のもうすこしあとでコミッ トされました。日付をもうすこし正確に指定して、リビジョン1.2を取ってきま しょう:

floss$ cvs -q update -D "1999-04-19 23:59:59"
U hello.c
U a-subdir/subsubdir/fish.c
U b-subdir/random.c
floss$ cvs status hello.c
===================================================================
File: hello.c                 Status: Locally Modified
   Working revision:  1.2     Sat Apr 24 22:45:22 1999
   Repository revision:       1.2     /usr/local/cvs/myproj/hello.c,v
   Sticky Tag:                (none)
   Sticky Date:               99.04.20.04.59.59
   Sticky Options:    (none)
floss$

こんなもんでしょうか。Sticky Date の行の日付と時刻をよく見てみると、午前 4:59:59を表示しているように見えますね、コマンドでは 11:59 を指定したはず なのに(sticky というのが何なのかというのは、あとで説明します)。御推察の 通り、このずれは地方時と Universal Coordinated Time (グリニッジ標準時)の 差が原因です。リポジトリは日付を Universal Time で保存しますが、クライア ント側の CVS は地方時を仮定します。今回の -D の場合、リポジトリ内の時刻 を比較することに興味があって、手元のシステムの時刻のことは気にしていない ので、少々運が悪かったですね。コマンド中に GMT を指定すれば回避できます:

floss$ cvs -q update -D "1999-04-19 23:59:59 GMT"
U hello.c
floss$ cvs -q status hello.c
===================================================================
File: hello.c                 Status: Up-to-date
   Working revision:  1.2     Sun Apr 25 22:38:53 1999
   Repository revision:       1.2     /usr/local/cvs/myproj/hello.c,v
   Sticky Tag:                (none)
   Sticky Date:               99.04.19.23.59.59
   Sticky Options:    (none)
floss$

いかがでしょう。こうすることで作業コピーは 4/19 の最終のコミットへと戻り ました(その日の最後の1秒のあいだにコミットしたのなら別ですが、しなかった ですから)。

今 update を走らせたらどうなるんでしょう?

floss$ cvs update
cvs update: Updating .
cvs update: Updating a-subdir
cvs update: Updating a-subdir/subsubdir
cvs update: Updating b-subdir
floss$

何も起きません。しかし、少なくとも3つのファイルに関してはもっと新しいバー ジョンがあったはずです。なぜそれらが作業コピーに入ってこないのでしょう。

ここで「sticky」の出番です。-D フラグでアップデート(「ダウンデート」かな?) すると、作業コピーは永続的にその日付以前に制限されることになります。CVS 用語で言うと、その作業コピーは「スティッキーデート」が設定された、という ことになります。作業コピーが一度スティッキーになると、そうでなくなるよう に指示されるまでスティッキーになったままです。ですから、続いて update を 実行しても自動的に最新のリビジョンを取ってきたりはしないのです。スティッ キーかどうかは、cvs status を実行するか、CVS/Entries ファイルを調べれば わかります:

floss$ cvs -q update -D "1999-04-19 23:59:59 GMT"
U hello.c
floss$ cat CVS/Entries
D/a-subdir////
D/b-subdir////
D/c-subdir////
/README.txt/1.1.1.1/Sun Apr 18 18:18:22 1999//D99.04.19.23.59.59
/hello.c/1.2/Sun Apr 25 23:07:29 1999//D99.04.19.23.59.59
floss$

ここで hello.c を変更してコミットしようとすると

floss$ cvs update
M hello.c
floss$ cvs ci -m "trying to change the past"
cvs commit: cannot commit with sticky date for file 'hello.c'
cvs [commit aborted]: correct above errors first!
floss$

CVS はコミットさせてくれません。それは時間を遡って過去を変えようとするよ うなものだからです。CVS はあらゆる記録をとろうとし、その結果、その操作を 許可しないのです。

しかしこれは CVS がその日以来コミットされてきたリビジョンを知らないとい う意味ではありません。スティッキーデートの設定された作業コピーも、未来の リビジョンを含めて比較できます。

floss$ cvs -q diff -c -r 1.5 hello.c
Index: hello.c
===================================================================
RCS file: /usr/local/cvs/myproj/hello.c,v
retrieving revision 1.5
diff -c -r1.5 hello.c
*** hello.c   1999/04/24 22:09:27     1.5
--- hello.c   1999/04/25 00:08:44
***************
*** 3,9 ****
  void
  main ()
  {
    printf ("Hello, world!\n");
-   printf ("between hello and goodbye\n");
    printf ("Goodbye, world!\n");
  }
--- 3,9 --
  void
  main ()
  {
+   /* this line was added to a downdated working copy */
    printf ("Hello, world!\n");
    printf ("Goodbye, world!\n");
  }

diff を見ると、1999/4/19 現在において hello の行と gooodbye の行の間の行 はまだ追加されていなかったということがわかります。作業コピーに加えた変更 も表示されていますね(コード断片の前にあるコメントを追加しました)。

スティッキーデート(やほかのスティッキー)を取り除くこともできます。update で -A を指定してください(-A はリセットという意味です、理由は聞かないでく ださい)、作業コピーが最新のリビジョンに戻ります:

floss$ cvs -q update -A
U hello.c
floss$ cvs status hello.c
===================================================================
File: hello.c                 Status: Up-to-date
   Working revision:  1.5     Sun Apr 25 22:50:27 1999
   Repository revision:       1.5     /usr/local/cvs/myproj/hello.c,v
   Sticky Tag:                (none)
   Sticky Date:               (none)
   Sticky Options:    (none)
floss$