トップ  |  更新  |  惑々  |  C++  |  Emacs  |  CVS  |  doxygen  |  VC/MFC  |  Libs  |  リンク

CVS How To

CVS (Concurrent Version System) とは、プロジェクトごとに、 ソースファイルの履歴を管理するツールである。 特に、複数のメンバーが参加している開発プロジェクトにおいて、 その威力を発揮するが、もちろん、一人で開発している場合でも 非常に有用である。


きっかけ

まず、人間というのは、間違う可能性のあるところでは 必ず間違いをやらかす存在である、という事実を肝に銘じておこう。 そして、プログラマも人間である。プロジェクトの進行中に、必ず、一つや二つは、 重大な間違いをしでかす。たとえば、私が過去にやった失敗には、

などがある。とくに最後の失敗は致命的だ。 スマキにされて大川に放り込まれても仕方がない (*)くらい、致命的だ。 今まで無事に生きてこられたのが不思議なほどである。 こんなことを繰り返したらさすがにヤバイ、ということで、 私もソースコード管理システムの導入を考えはじめたわけである。

(*) たとえが、古すぎ

なぜに CVS

その昔、RCSを使っていた時期があったが、ふと気づくと、 まったく使わなくなってしまっていた。なんとなく面倒くさいなあ、 という感じで、いつの間にか使わなくなっていたのだが、 CVS を常用している今から考えると、次のような理由が挙げられようか。

余談ながら、『達人プログラマー』(*)という書物の 「17 ソースコード管理」 (89ページ) によると、

でも今のチームはソースコード管理システムを使っていないんだけど…

  恥ずかしいと思ってください!
(*) アンドリュー・ハント / デビッド・トーマス著、村上雅章訳、ピアソンエデュケーション

とある。「…ごめんなさい。」と、思わず謝ってしまいたくなるが、 本当に恥ずかしながら、 CVS を使い始めたのは、ここ1年くらいのことである。

CVS を使い始めてわかったのは、

ということである。上に挙げた「RCSの欠点」というのは、何のことはない、 このことの裏返しなのであった。


導入

最近の Linux ディストリビューションを使っているなら、 CVSは、たいてい最初からインストールされていると思う。

% /usr/bin/cvs -v
% /usr/local/bin/cvs -v

を実行してみて、

Concurrent Versions System (CVS) 1.10.8 (client/server)

というようなメッセージが表示されれば、すでにインストール済みである。 バージョン番号の 「1.10.8」 のところは、最新版では、1.11 になっているはず。

不幸にも CVS がインストールされていなかった場合は、 バイナリパッケージを探し出してきてインストールするか、あるいは、 本家 からソース一式をダウンロードして、 ビルド & インストールを敢行してほしい。なに、インストールのやり方は、 GNU 標準の、configure; make; make install 方式 (のはず) だから、 とくに難しいことはない。


リポジトリ vs. 作業コピー

CVSは、ソースコードの修正履歴などを保持するファイルを、 リポジトリと呼ばれる保管場所に格納して管理する。

リポジトリは共有することができる。 プロジェクトのメンバーは、CVSのコマンドを介して、 リポジトリから個人用の作業コピーを取り出す。 各人は、自分が取り出した作業コピーに対して修正を加える。

修正を受けた作業コピーは、その修正内容を、 リポジトリ内の履歴ファイルにマージすることができる。 マージが正常に完了すると、履歴ファイルに保持されている最新リビジョンの内容と、 手元の作業コピーのファイルの内容は、同一となる。

このように、リポジトリと作業コピーを分離した上で、 作業コピーにおける修正箇所をリポジトリ内の履歴ファイルにマージすることによって 両者の同期を確保していく、という仕組みを採用することで、 複数のメンバーが同じファイルに対する修正とマージを並行して行うことも、 できるようになっているのである。

これこそが、CVSの最大の利点であると言えよう。


準備

まずは、履歴を格納する場所となる、リポジトリを作成する。やり方は簡単。 次のコマンドを実行するだけである。

% cvs -d dir_name init 

dir_name は、リポジトリとなるディレクトリのパス名である。 このディレクトリは、あらかじめ作成しておく必要はない。 cvs init が勝手に作ってくれる。

なお、以下、このリポジトリのパスを ${CVSROOT}/ で参照することにする。 なぜならば、環境変数 CVSROOT が設定されていると、 -d で明示的に指示しないかぎり、cvs は、 CVSROOT の設定内容をリポジトリパスとして使用するからである。

この作業は、通常、システム管理者の仕事となるが、 別に一般ユーザが自分のホームディレクトリの下に個人用のリポジトリを作ってもかまわない。 「リポジトリの場所」というのがホストごとに一意に決められているわけではなく、 cvs は、実行されるたびごとに、コマンドラインオプションや環境変数によって 指定されたディレクトリをリポジトリであるとみなして処理を行うからである。

というわけで、これから CVS に詳しくなりたいという人は、 まず個人的なリポジトリを作って、そこでいろいろ実験されるのがよかろう。

cvs init を実行すると、${CVSROOT}/ の下に、 CVSROOT という名前のディレクトリが作成され (はは、紛らわしいね)、そこに、種々の管理用ファイルが置かれることになる。 図示すると、こんな感じ。

  ${CVSROOT}/
    └─ CVSROOT/
          └┬ Emptydir/
            ├ checkoutlist
            ├ checkoutlist,v
               ……
               ……
            ├ verifymsg
            └ verifymsg,v
実は、この CVSROOT/ 自体も cvs によって管理されている。

${CVSROOT}/ の下は、 CVSROOT/ も含め、cvs を起動したユーザの権限でアクセスが行われる。 したがって、${CVSROOT}/ 自体は、cvs を使用するユーザなら誰でも 読み書き可能にしておかなければならない。グループ id とそのアクセス権を確認し、 必要なら修正しておこう。

CVSROOT/ の下のファイルについては、 管理者だけが書き込み可能というようにしておいたほうがよいだろう。 ただし、何事にも例外はつきもの。history および val-tags というファイルは、誰でも読み書きできるようにしておく必要がある。

リポジトリの仕組み

ここで、ちょっと、リポジトリがどういう構造になっているかを説明しておいたほうが良いだろう。 というのも、はじめて CVS に触れる人にとっては、リポジトリというのは、たぶん、 「えたいの知れない怖い場所」 のように思えるに違いないからだ。 なんたって、私自身が最初はそう思ってたんだからそうに違いない。そうだよね? ね?

…とにかく、だ、結論を先に言うと、リポジトリは、 RCS ファイルを格納する、ただのディレクトリ」 に過ぎない。

RCS (Revision Control System) は、ファイル単体で履歴を管理するシステムである。 ここでは、その履歴ファイルを「RCSファイル」と呼んでいる。ファイル名の末尾に、",v" が付くのが特徴である。

どんなモジュールやファイルがあるか、とか、 あるいは、あのファイルのリビジョンはいくつで、このファイルのリビジョンはこれこれだ、 とかいうような情報を一手に握るデータベースみたいなのは存在しないのである。

CVSROOT/modules がソレに該当するのではないか、という意見があるかもしれない。 このファイルについては、後ほど説明しよう。

言ってみれば、「ファイルシステムそのものがデータベース」 である。そして、ファイルのリビジョンに関する情報は、そのRCSファイル自身が保持している。 というか、それ以外には、どこにも保持されていないのだ。

あるモジュールに属する全ファイルの最新リビジョンを取り出したいと思ったら、 各ファイルを一つずつ調べて、 最新リビジョンをチェックアウトするしかないのである。

「モジュール」とは、ソフトウェアを構成するファイルの集合体のことだと思ってほしい。 あるいは、「プロジェクト」と言い替えてもよい。

あるいは、モジュールに属する、とあるファイルの名前を変えたいと思ったら、 そのRCS ファイルを rename してしまってもよいのである。 さらには、RCS ファイルを削除すれば、 そのファイルは最初から存在していなかったことになる。

もちろん、これは相当に強引な方法なので、一般的にはお勧めできない。 より安全な方法については、後で説明する。

RCS を使ったことがある人なら、作業ディレクトリにあった RCS/ というディレクトリが、(名前だけはモジュール名に変わるが) そのまま、 ${CVSROOT} の下に移動したと思ってもらえば、分かりやすいだろう。

とにかく、リポジトリに置かれるファイルは、単なる RCS ファイルだけだ、 ということを覚えておいてほしい。そして、これは重要なことだが、前項でも述べたように、 リポジトリ内のファイルは、「誰でも読み書きできる」ようになっている。 うかつにアクセスして、「大事なファイルを消しちゃった」 なんてことがないように、充分に注意していただきたい。


リポジトリの仕組み (その2)

前項では、説明をちょっと単純化しすぎたかもしれない。 実際には、リポジトリディレクトリの直下には、,v ファイルを置くことはできない。 リポジトリ直下に置かれるのは、「モジュール」として扱われるディレクトリだけだ。 ,v ファイルは、このモジュールディレクトリの下に置かなければならない。

モジュールディレクトリの下は、好きなようにディレクトリを配置してかまわない。 たとえば、module-Amodule-B などのモジュールが 存在して、以下のような構成になっていてもよい。

  ${CVSROOT}/
    └┬─ CVSROOT/
      │
      ├┬ module-A/
      │└┬ README,v
      │  ├ INSTALL,v
      │  └┬ src/
      │    ├─ Makefile
      │    ├─ foo.c,v 
      │    └─ bar.c,v
      │
      └┬ module-B/
        └─ 省略

つまり、module-A の下には、README,v および INSTALL,v という、 2つの ,v ファイルと、ソースファイルを収める src というディレクトリが置かれている。 さらに、src の下には、いくつかのプログラムソースファイルが置かれる、 という構成になっているわけだ。

このような構成の整合性を保証するために、モジュールを作成する import コマンドや、 作業コピーを作る checkout コマンドは、モジュールディレクトリを対象とする操作となっている。

checkout においては、直接、ファイルを指定することもできる。が、その場合でも、 モジュールのトップディレクトリからそのファイルに至るまでの すべてのディレクトリ階層が作成される。
(つづく…)

リンク

初出: 2001年4月20日


トップページへ / Last modified: 2001-10-07 17:03:29 JST
Created by OKA Toshiyuki < oka-t@fides.dti.ne.jp >