Node: Marking A Moment In Time (Tags), Previous: Acceptable Date Formats, Up: Other Useful CVS Commands



Marking A Moment In Time (Tags)

日付を指定してアクセスする方法は、単なる時間の経過が主な関心事であれば便 利かもしれません。しかし、本当は特定のイベントが起こった時点でのプロジェ クトの状態にアクセスしたい、ということのほうが多いと思います。それはたと えばリリースの時点であったり、ソフトウェア開発が安定したある時点であった り、主要な機能を追加または削除した時点であったりするわけです。

そのイベントが起こった日付を思い出そうとしたり、ログメッセージを読んでそ の日付を推測したりするのは、さぞかし退屈な作業でしょう。おそらく、そのよ うなイベントは重要なのでしょうから、リビジョン履歴のなかにそのようにきち んと記録されています。CVS でそのようなマークをつける方法は タグ付け (tagging) といいます。

タグはコミットとは違い、ファイルの特定の変更を記録するわけではなくて、開 発者のファイルへの姿勢に変更があることを記録します。タグとは、ある開発者 の作業コピーで表わされる、リビジョンの集合につけられたラベルです(通常、 そのような作業コピーは完全に最新なので、タグ名はリポジトリ内の「最新で最 良の」リビジョンにつけられます)。

タグをセットするのは簡単です、こんな感じ:

     floss$ cvs -q tag Release-1999_05_01
     T README.txt
     T hello.c
     T a-subdir/whatever.c
     T a-subdir/subsubdir/fish.c
     T b-subdir/random.c
     floss$
     

このコマンドで、この作業コピーで表されるスナップショットにシンボル名 "Release-1999_05_01" を関連づけます。きちんと定義すると、スナップショッ トとは、プロジェクトのファイルと関連づけられたリビジョン番号の集合です。 これらのリビジョン番号はファイル同士で同じである必要はなく、実際、違うこ とのほうが多いです。たとえば、この章でずっと使っている myproj ディレクト リでタグをつけて、その作業コピーが完全に最新だったと仮定すると、 シンボル名 "Release-1999_05_01" は hello.c はリビジョン1.5、fish.c はリ ビジョン1.2、random.c はリビジョン1.2、その他はリビジョン1.1につきます。

タグを線で表わしてプロジェクト内のファイルのいろいろなリビジョンをつない で可視化するとわかりやすいと思います。Figure 2.1 では、あるプロジェクト 内でタグ付けされた各ファイルのリビジョン番号を線でつないでみました。

     
          File A      File B      File C      File D      File E
          ------      ------      ------      ------      ------
          1.1         1.1         1.1         1.1         1.1
      ----1.2-.       1.2         1.2         1.2         1.2
          1.3 |       1.3         1.3         1.3         1.3
               \      1.4       .-1.4-.       1.4         1.4
                \     1.5      /  1.5  \      1.5         1.5
                 \    1.6     /   1.6   |     1.6         1.6
                  \   1.7    /          |     1.7         1.7
                   \  1.8   /           |     1.8       .-1.8------->
                    \ 1.9  /            |     1.9      /  1.9
                     `1.10'             |     1.10    /   1.10
                      1.11              |     1.11    |
                                        |     1.12    |
                                        |     1.13    |
                                         \    1.14    |
                                          \   1.15   /
                                           \  1.16  /
                                            `-1.17-'
     
     [Figure 2.1: How a tag might stand in relation to files's revisions.]
     
     

線をひっぱってピンとさせて、それに沿って見ると、そのプロジェクトの履歴中 の特定の時点が見えてきます。すなわち、その時点でタグがセットされたのです (Figure 2.2)。

     
          File A      File B      File C      File D      File E
          ------      ------      ------      ------      ------
                                              1.1
                                              1.2
                                              1.3
                                              1.4
                                              1.5
                                              1.6
                                              1.7
                      1.1                     1.8
                      1.2                     1.9
                      1.3                     1.10        1.1
                      1.4                     1.11        1.2
                      1.5                     1.12        1.3
                      1.6                     1.13        1.4
                      1.7         1.1         1.14        1.5
                      1.8         1.2         1.15        1.6
          1.1         1.9         1.3         1.16        1.7
      ----1.2---------1.10--------1.4---------1.17--------1.8------->
          1.3         1.11        1.5         1.17        1.9
                                  1.6         1.17        1.10
     
     [Figure 2.2: The same tag as a "straight sight" through the revision history.]
     
     

続けてファイルを編集し、コミットしても、タグはリビジョン番号が増えるにつ れて動いたりしません。固定したまま、タグづけられた時点での各ファイルのリ ビジョン番号にくっついています(スティッキー)。

タグは記述子として重要性があるにもかかわらず、ログメッセージにタグのこと が含まれなかったり、that the tags themselves can't be full paragraphs of prose というのは少し不幸です。前の例ではタグ自身が、そのプロジェクトが ある日付でのリリース状態であることを明白に説明しています。しかし、もう少 し複雑な状態のスナップショットを作りたいこともあるでしょう、そうするとタ グ名はこんなに見苦しくなってしまいます:

     floss$ cvs tag testing-release-3_pre-19990525-public-release
     

一般的な規則として、タグ名はできるだけ簡潔に、そして記録しようとしている イベントについての情報を必要十分に含んでいるよう心がけるべきです。迷った 時は、説明しすぎるほうへ振っておいたほうがいいでしょう。あとになって、そ の時の状況を正確に記述した冗長なタグ名から何かわかって、嬉しいこともある でしょう。

タグ名にピリオドやスペースが使われていないのに気づいたと思います。CVS で は有効なタグ名を構成するものについてはちょっと厳しいのです。英字で始まり、 英数字、ハイフン("-")、アンダスコア("_")で構成される、というのがそのルー ルです。スペースやピリオド、コロン、カンマ、記号は使えません。

タグ名でスナップショットにアクセスするには、タグ名をリビジョン番号のよう に使えばいいのです。スナップショットへのアクセスには2通りの方法がありま す: あるタグを指定して新しい作業コピーをチェックアウトするか、またはタグ を指定して既存の作業コピーに上書きするか、です。どちらの方法でも、作業コ ピー中のファイルは指定したタグのリビジョンになっています。

たいがいの場合やりたいことというのは、そのスナップショットの時点でプロジェ クトがどんなだったかちょっと見たい、というくらいのことだと思います。その ような場合だと、自分が今作業していて、コミットしていない変更があったり何 か便利な状態が構築してあったりするようなメインの作業コピーでそんなことは あんまりしたくないでしょうから、タグを指定して別の作業コピーをチェックア ウトしたいんだということにしましょう。このようにします(これは今ある作業 コピーとは別の場所、1つ上のディレクトリとか、に居ることを確認してから実 行してくださいね!)

     floss$ cvs checkout -r Release-1999_05_01 myproj
     cvs checkout: Updating myproj
     U myproj/README.txt
     U myproj/hello.c
     cvs checkout: Updating myproj/a-subdir
     U myproj/a-subdir/whatever.c
     cvs checkout: Updating myproj/a-subdir/subsubdir
     U myproj/a-subdir/subsubdir/fish.c
     cvs checkout: Updating myproj/b-subdir
     U myproj/b-subdir/random.c
     cvs checkout: Updating myproj/c-subdir
     

update コマンドで -r オプションを見てきました、あれはそのあとにリビジョ ン番号をつけましたよね。多くの場合、タグはリビジョン番号のように使えます。 それは、各ファイルにとってみればタグというのは単に、対応するひとつのリビ ジョン番号をさしているだけだからです(ひとつのプロジェクトで同じ名前のタ グをふたつ持つというのは違反ですし、一般には不可能です)。実際、CVS でリ ビジョン番号を使うようなところではどこでも、かわりにタグ名が使えます(タ グがセットされていさえすれば)。あるファイルについて、現状と最後のリリー ス時点間の diff を取りたければこのようにします:

     floss$ cvs diff -c -r Release-1999_05_01 hello.c
     

一時的にそのリビジョンに戻したければこのようにします:

     floss$ cvs update -r Release-1999_05_01 hello.c
     

タグとリビジョンのこの変換可能性から、有効なタグ名の厳しいルールの理由が 説明できます。タグ名にピリオドを許したらどうなりますか? 実際のリビジョン 番号"1.47"に"1.3"というタグ名をつけることができてしまいますよね。その後 にこういうコマンドを実行したとすると

     floss$ cvs update -r 1.3 hello.c
     

これが "1.3" というタグを指定しているのか、もっと前のリビジョン1.3を指定 しているのか、CVS はどうやって判断すればよいのでしょう。このせいでタグ名 が制限してあって、CVS はタグ名とリビジョン番号の区別を容易に判断できるよ うになっています。リビジョン番号にはピリオドがあって、タグ名にはありませ ん。(ほかの制限も同じ理由によります、CVS がタグ名を認識しやすいようになっ ているのです)

さてここで、そろそろだろうなと思ったことと思いますが、スナップショットに アクセスする2つめの方法を紹介します。既存の作業コピーをタグ付けされたリ ビジョンに切り替えるやつです、これも update でやります:

     floss$ cvs update -r Release-1999_05_01
     cvs update: Updating .
     cvs update: Updating a-subdir
     cvs update: Updating a-subdir/subsubdir
     cvs update: Updating b-subdir
     cvs update: Updating c-subdir
     floss$
     

上記のコマンドは、以前 hello.c を Release-1999_05_01 に戻すときに 使ったものとほとんど同じです。ファイル名の指定がないところだけが違います、 今回はプロジェクト全体を元に戻したいですからね。(もしやりたければプロジェ クトのサブツリーだけをタグの時点に戻すこともできます。上のコマンドをトッ プレベルではなくてサブツリー内で実行してください。あんまりそうしたい機会 が多いとも思えませんけど)

アップデートの時点では、どのファイルも変更されていないように見えることに 注意してください。作業コピーはタグ付けされた時点では最新でしたし、それ以 来変更はコミットされていません。

しかしこれは何も変更されていないということを意味しません。作業コピーはこ れがタグ付けされたリビジョンであることを知っています。ここで変更を加えて コミットしようとすると(hello.c を変更したとしましょう):

     floss$ cvs -q update
     M hello.c
     floss$ cvs -q ci -m "trying to commit from a working copy on a tag"
     cvs commit: sticky tag 'Release-1999_05_01' for file 'hello.c' is not a branch
     cvs [commit aborted]: correct above errors first!
     floss$
     

CVS はコミットを許しません。(エラメッセージの正確な意味についてはいまの ところ放っておいていいです、ブランチについては次で説明します) これはタグ で指定されたこの作業コピーがチェックアウトされたものかアップデートされた ものかには関係ありません。いったんタグで指定したら、CVS はその作業コピー を履歴のある一時点でのスタティックなスナップショットだと見なし、履歴を変 更させなくなります。少なくとも簡単にはさせてくれません。cvs status を実 行するか、CVS/Entries ファイルを見ると、スティッキータグが各ファイルに設 定されているのがわかります。たとえばトップレベルの Entries ファイルはこ うなっています:

     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//TRelease-1999_05_01
     /hello.c/1.5/Tue Apr 20 07:24:10 1999//TRelease-1999_05_01
     floss$
     

ほかのスティッキーと同じように、タグも -A フラグつきの update を実行すれ ば削除できます:

     floss$ cvs -q update -A
     M hello.c
     floss$
     

hello.c に加えた変更は失われません、CVS is still aware that the file changed with respect to the repository:

     floss$ cvs -q diff -c 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/20 06:12:56     1.5
     --- hello.c   1999/05/04 20:09:17
     ***************
     *** 6,9 ****
     --- 6,10 --
         printf ("Hello, world!\n");
         printf ("between hello and goodbye\n");
         printf ("Goodbye, world!\n");
     +   /* a comment on the last line */
       }
     floss$
     

update でリセットしたので、CVS はコミットさせてくれます:

     floss$ cvs ci -m "added comment to end of main function"
     cvs commit: Examining .
     cvs commit: Examining a-subdir
     cvs commit: Examining a-subdir/subsubdir
     cvs commit: Examining b-subdir
     cvs commit: Examining c-subdir
     Checking in hello.c;
     /usr/local/cvs/myproj/hello.c,v  <-  hello.c
     new revision: 1.6; previous revision: 1.5
     done
     floss$
     

もちろん、Release-1999_05_01 というタグはリビジョン1.5についたま まです。タグ以前と以降のリビジョンのステータスを比べてみてください:

     floss$ cvs -q status hello.c
     ===================================================================
     File: hello.c                 Status: Up-to-date
        Working revision:  1.6     Tue May  4 20:09:17 1999
        Repository revision:       1.6     /usr/local/cvs/myproj/hello.c,v
        Sticky Tag:                (none)
        Sticky Date:               (none)
        Sticky Options:            (none)
     floss$ cvs -q update -r Release-1999_05_01
     U hello.c
     floss$ cvs -q status hello.c
     ===================================================================
     File: hello.c                 Status: Up-to-date
        Working revision:  1.5     Tue May  4 20:21:12 1999
        Repository revision:       1.5     /usr/local/cvs/myproj/hello.c,v
        Sticky Tag:                Release-1999_05_01 (revision: 1.5)
        Sticky Date:               (none)
        Sticky Options:            (none)
     floss$
     

CVS は歴史を変えさせてくれない、と言いました。さて、今から歴史を変える方 法を教えます。