ノード:RCS Format, 次:What Happens When You Remove A File, 前:Repository Structure, 上:Repository Administration
CVS を使うにあたり、RCS 形式について知っておく必要は一切ありません(ソー
スディストリビューションに素晴らしい記事がありますけれど。doc/RCSFILES
をご覧ください)。しかし、この形式の基本的なところを理解していると CVS
のトラブルシューティングに非常に役に立ちますので、ファイルの1つ
hello.c,v
をちょっと覗いてみることにしましょう。ファイル内容を示します:
head 1.1; branch 1.1.1; access ; symbols start:1.1.1.1 jrandom:1.1.1; locks ; strict; comment @ * @; 1.1 date 99.06.20.17.47.26; author jrandom; state Exp; branches 1.1.1.1; next; 1.1.1.1 date 99.06.20.17.47.26; author jrandom; state Exp; branches ; next; desc @@ 1.1 log @Initial revision @ text @#include <stdio.h> void main () { printf ("Hello, world!\n"); } @ 1.1.1.1 log @initial import into CVS @ text @@
うひゃー! もうほとんど無視してもかまわないです; 例えば 1.1 と 1.1.1.1
の関連や、暗黙の 1.1.1 ブランチとかは気にしないで下さい、ユーザ、管理
者、どちらの観点からもあまり重要なことではありません。理解すべきは全体
のフォーマットです。最初はヘッダフィールドのコレクションです:
head 1.1; branch 1.1.1; access ; symbols start:1.1.1.1 jrandom:1.1.1; locks ; strict; comment @ * @;
そのあとは各リビジョンのメタ情報のグループです(リビジョンの中身はまだ
先です)、こんな感じ:
1.1 date 99.06.20.17.47.26; author jrandom; state Exp; branches 1.1.1.1; next ;
最後にログメッセージと実際のリビジョンのテキストが来ます:
1.1 log @Initial revision @ text @#include <stdio.h> void main () { printf ("Hello, world!\n"); } @ 1.1.1.1 log @initial import into CVS @ text @@
よくみると、最初のリビジョンの内容が 1.1 という見出しの下にあって、そ
のログメッセージがなぜか "Initial revision" になっています。インポート
時に使ったのは "initial import into CVS" というログメッセージなのに。
そっちのログメッセージはもっと下のほう、Revision 1.1.1.1
の下に
あります。今この矛盾を気にする必要はありません。これはインポートが特別
な場合だから起こることなのです。It happens because imports are a special
circumstance: Inorder to make repeated imports into the same project
have a usefuleffect, import actually places the initial revision on both
the maintrunk and on a special branch (これの理由は Advanced CVS
でベンダブランチについて述べるときにもう少し明らかになります). 今のと
ころは 1.1
と 1.1.1.1
を同じものとして扱っても構いません。
hello.c の最初の変更をコミットすると、このファイルのことがもう少しわか
ってきます:
floss$ cvs -Q co myproj floss$ cd myproj floss$ emacs hello.c (ファイルを変更してみる) floss$ cvs ci -m "print goodbye too" cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in hello.c; /usr/local/newrepos/myproj/hello.c,v <-- hello.c new revision: 1.2; previous revision: 1.1 done
ここでリポジトリ内の hello.c,v を見ると、コミットの結果がわかります:
head 1.2; access; symbols start:1.1.1.1 jrandom:1.1.1; locks; strict; comment @ * @; 1.2 date 99.06.21.01.49.40; author jrandom; state Exp; branches; next 1.1; 1.1 date 99.06.20.17.47.26; author jrandom; state Exp; branches 1.1.1.1; next ; 1.1.1.1 date 99.06.20.17.47.26; author jrandom; state Exp; branches; next ; desc @@ 1.2 log @print goodbye too @ text @#include <stdio.h> void main () { printf ("Hello, world!\n"); printf ("Goodbye, world!\n"); } @ 1.1 log @Initial revision @ text @d7 1 @ 1.1.1.1 log @initial import into CVS @ text @@
リビジョン1.2全体の内容がファイルに保存されており、リビジョン1.1の内容
は暗号ちっくな形式に置き換わっています:
d7 1
d7 1
は「7行目から始めて、1行削除する」という意味の diff コー
ドです。言い換えると、リビジョン1.1を導出するにはリビジョン1.2から7行
目を削除する、ということなのです! 自分で実際にやってみてください。これ
でリビジョン1.1ができるのがわかると思います。単純に、ファイルに追加し
た行をなくすだけです。
これは RCS 形式の基本原則を示しています: リビジョン間の相違のみを保存 し、そうすることによって各リビジョンそれぞれの全体を保存するのに比べて 容量を節約します。一番新しいリビジョンから以前のリビジョンへ戻るには、 保存してある diff をより最近のリビジョンに対して patch すればよろしい。 つまりこれは、過去に戻ろうとすればするほど、より多くの patch 操作が必 要になる、ということです(たとえばリビジョン1.7のファイルがあって、その ファイルのリビジョン1.4へのアクセスを要求された場合、patch で 1.7 から 1.6 を生成し、1.6 から 1.5 を、そして 1.5 から 1.4 を生成します)。幸い、 古いリビジョンはあまりアクセスされませんので、実用上 RCS システムはう まく動きます。最近のファイルになるほど取得するコストが低いわけです。
ファイルの冒頭のヘッダ情報が何を意味するか、全てを理解する必要はありませ ん。しかし、ある種の操作は、結果がとても明確にヘッダに示されますので、ヘッ ダに親しんでおくと便利には違いありません。
トランクに新しいリビジョンをコミットした時、head
ラベルが更新され
ます(先に示した例で、2回目に hello.c をコミットした時、そのラベルがどの
ように 1.2 になったか注意して見てみてください)。あるファイルをバイナリと
して追加した時、あるいはタグをつけた時にも、それらの操作はヘッダに記録さ
れます。例として foo.jpg をバイナリファイルとして追加し、その後二度ほど
タグづけしてみましょう:
floss$ cvs add -kb foo.jpg cvs add: scheduling file 'foo.jpg' for addition cvs add: use 'cvs commit' to add this file permanently floss$ cvs -q commit -m "added a random image; ask jrandom@red-bean.com why" RCS file: /usr/local/newrepos/myproj/foo.jpg,v done Checking in foo.jpg; /usr/local/newrepos/myproj/foo.jpg,v <-- foo.jpg initial revision: 1.1 done floss$ cvs tag some_random_tag foo.jpg T foo.jpg floss$ cvs tag ANOTHER-TAG foo.jpg T foo.jpg floss$
さて、リポジトリ内の foo.jpg,v のヘッダ部分を見てみましょう:
head 1.1; access; symbols ANOTHER-TAG:1.1 some_random_tag:1.1; locks; strict; comment @# @; expand @b@;
最後の expand の行の b を見て下さい。これはこのファイルを -kb つきで add したためにこうなっています。通常のテキストファイルでは、チェックアウトと アップデートの時にキーワードや改行コードの変換が行われるのですが、このファ イルではそれが行われない、という意味です。タグは symbols セクションに 1 タグ1行で記してあります。最初のリビジョンに2回タグをつけたので、タグは両 方とも最初のリビジョンについています。(タグ名に英数字、ハイフン、アンダ スコアしか使えない理由もこれで説明できます。タグがコロンやピリオドを含ん でいたとしたら、RCS ファイルのこの欄のタグとリビジョンの区切りが曖昧になっ てしまうからですね。)
RCS ファイル中の @
シンボルはフィールド(訳注: フィールドとは各リ
ビジョンの領域のことのようです)の区切りに使用されますので、ファイルのテ
キスト中やログメッセージに出てくる場合にはクオートする必要があります(そ
うしないと CVS はそれをフィールドの最後だと誤解してしまいます)。クオート
するには を2つ続けます。つまり、CVS は @@
が出てくると、フィー
ルドの終わりという意味ではなく、@ 記号であると解釈します。foo.jpg をコ
ミットしたときのログメッセージは
"added a random image; ask jrandom@red-bean.com why"
でした、これは foo.jpg,v 中ではこのようになります:
1.1 log @added a random image; ask jrandom@@red-bean.com why @
ログメッセージにアクセスするときにはj random@@red-bean.com の中の @
記号は自動的にクオートがはずされます:
floss$ cvs log foo.jpg RCS file: /usr/local/newrepos/myproj/foo.jpg,v Working file: foo.jpg head: 1.1 branch: locks: strict access list: symbolic names: ANOTHER-TAG: 1.1 some_random_tag: 1.1 keyword substitution: b total revisions: 1; selected revisions: 1 description: ---------------------------- revision 1.1 date: 1999/06/21 02:56:18; author: jrandom; state: Exp; added a random image; ask jrandom@red-bean.com why ============================================================================ floss$
RCS ファイルを手で編集する時くらいしか気にすることはないです(ほとんどな いとは思いますが、全然ないわけではありません)。その場合はリビジョン内容 とログメッセージで 記号を2つ重ねて書くことを思い出してください。もし忘 れたら、RCS ファイルはむちゃくちゃになり、思いもかけないヘンな動作をする でしょう。
Speaking of hand-editing RCS files, don't be fooled by the permissions
in the repository:
floss$ ls -l total 6 -r--r--r-- 1 jrandom users 410 Jun 20 12:47 README.txt,v drwxrwxr-x 3 jrandom users 1024 Jun 20 21:56 a-subdir/ drwxrwxr-x 2 jrandom users 1024 Jun 20 21:56 b-subdir/ -r--r--r-- 1 jrandom users 937 Jun 20 21:56 foo.jpg,v -r--r--r-- 1 jrandom users 564 Jun 20 21:11 hello.c,v floss$
(Unix の ls の出力に詳しくない人へ、左のほうの -r--r--r--
は、そ
のファイルは読めるけど変更できないよ、という意味です) これらのファイルは
誰に対してもリードオンリーのように見えますが、ディレクトリパーミッション
のほうを考慮に入れなくてはなりません:
floss$ ls -ld . drwxrwxr-x 4 jrandom users 1024 Jun 20 22:16 ./ floss$
myproj/ 自身とそのサブディレクトリは、オーナ(jrandom)とグループ(users)の 書き込み権限があります。これはつまり、(jrandom 及び users グループの メンバーなら誰でも、の権限で実行される) CVS はそれらのディレクトリでファ イルを作ったり削除したりできるということです、既に存在するファイルを直接 編集することができないとしても。CVS は RCS ファイルのコピーを取って編集 するので、あなたも一時コピーを好きなように変更し、既存の RCS ファイルを その新しいファイルで置き換えたっていいのです。(なんでファイルがリードオ ンリーなのかというのは聞かないでください、RCS がスタンドアロンで動く時の 動作のしかたに関係のある歴史的経緯があるのです)
ついでに言うと、リポジトリのトップレベルディレクトリのグループが
cvs
であることを考えれば、それらのファイルのグループが
users
になっているのは望ましいことではないと思います。リポジトリ
内でこのコマンドを実行すれば問題を解決できます:
floss$ cd /usr/local/newrepos floss$ chgrp -R cvs myproj
リポジトリ内に新しく作成されるファイルのグループについては、Unix の通常 のファイル作成時のルールが適用されてしまうので、たまにリポジトリ内のファ イルやディレクトリを chgrp または chmod してやる必要があると思います。 リポジトリのパーミッションをどう構成するかについて、難しい固定した規則 はありません、単にどのプロジェクトで誰が作業しているかによります。