UNIX/Linuxの部屋 CVSチュートリアル基礎編コマンドの使い方

TOP UNIX/Linuxの部屋 UNIX/Linuxコマンド一覧 用語集 新版 由来/読み方辞書 環境変数マニュアル Cシェル変数 システム設定ファイル システムコール・ライブラリ ネットワークプログラミングの基礎知識 クラウドサービス徹底比較・徹底解説




コマンド CVSチュートリアル基礎編 バージョン管理ツール (基礎編) このエントリーをはてなブックマークに追加

CVS はファイルのバージョン管理を行うツールである。FreeBSD・NetBSD・OpenBSD・ Apache・Darwin などの数多くのオープンソースプロジェクトが CVS を採用している。ちなみに当ページのコンテンツは CVS を用いて管理している。

利点
CVS を使うことの利点は以下のとおり。
ファイルの変更履歴を記録できる。
⇒ 古いバージョンに戻すことができる。
⇒ ファイルの修正中に、どの部分をどう修正したかを確認できる。
正確なリリース作業が行える。
⇒ ファイルを転送し忘れた、古いファイルをリリースしてしまった、ということがない
複数人での作業ができる。
⇒ 複数人でひとつのファイルを編集できる。

用語
まずは以下の用語を覚えてほしい。
リポジトリ
ファイルの保管庫。ファイル内容と、過去の修正履歴が格納されている。リポジトリの実体はただのテキストファイルであるが、これを直接修正することはまずない。「レポジトリ」と表記する人もたまにいる。
チェックアウト
リポジトリからファイルを取り出すこと。チェックアウトした後は、ファイルを眺めたり、ファイルを修正したりする。
コミット
チェックアウトしたファイルを修正した後に、リポジトリへ反映すること。
リビジョン
ファイルごとに振られる版数のこと。初期登録時は 1.1 で、コミットを重ねるたびに、1.2・1.3・1.4 … 1.99・1.100・1.101 … と上がっていく。

書式
CVS に関する操作を行うには cvs コマンドを使用する。cvs コマンドの書式は
% cvs [共通オプション] [サブコマンド] [サブコマンドオプション] [サブコマンド引数]
である。サブコマンドとは init・checkout・diff・commit などがあり、サブコマンドが異なるとサブコマンドオプションやサブコマンド引数の意味が異なる (CVS のマニュアルでは init・checkout などをコマンドと命名しているが、ここではあえてサブコマンドと表記している)。

共通オプションとサブコマンドオプションは全く異なるものである。例えば
% cvs -d /home/68user/cvsroot checkout -d source project-a
は -d が 2つあるが、意味は全然違う。最初の -d は共通オプションで、リポジトリの場所を指定している。2つ目の -d はサブコマンド checkout のサブコマンドオプションで、チェックアウト先のディレクトリを指定するオプションである。

リポジトリ初期化 (init)
リポジトリの初期化には cvs init コマンドを使用する。まず、リポジトリを置く場所を決めよう。当ページ管理人の場合は、/home/68user/cvsroot/ というディレクトリをリポジトリ置き場としている。あらかじめディレクトリを作成する必要はなく、いきなり cvs init すればよい。なお、リポジトリの場所は (相対パスではなく) フルパスで指定すること。
% cvs -d /home/68user/cvsroot init
これにより、以下のファイル・ディレクトリが自動的に生成される。
/home/68user/cvsroot/
/home/68user/cvsroot/CVSROOT
/home/68user/cvsroot/CVSROOT/Emptydir
/home/68user/cvsroot/CVSROOT/loginfo
/home/68user/cvsroot/CVSROOT/loginfo,v
/home/68user/cvsroot/CVSROOT/rcsinfo
/home/68user/cvsroot/CVSROOT/rcsinfo,v
/home/68user/cvsroot/CVSROOT/editinfo
/home/68user/cvsroot/CVSROOT/editinfo,v
(略)
cvsroot/ の下には CVSROOT/ というディレクトリが作成されているが、これはリポジトリ設定用のファイルなので、とりあえずは気にしなくてよい。

今後 cvs コマンドを使うたびにリポジトリの場所を共通オプション -d で指定するのは面倒なので、環境変数 CVSROOT に設定しておこう。これで共通オプション -d は不要になる。
% setenv CVSROOT /home/68user/cvsroot (csh・tcsh の場合)
% CVSROOT=/home/68user/cvsroot; export CVSROOT (sh・bash の場合)

インポート (import)
リポジトリを作成したら、管理したいファイルを cvs import でインポートする。もしとりあえず CVS を試してみたいだけなら、以下のサンプルプログラムを使うとよい。

ファイル・ディレクトリ構成
  • hello/
  • hello/hello.c
  • hello/Makefile
hello/hello.c
#include 
main(){
    printf("Hello, world.\n");
    return 0;
}
hello/Makefile
TARGET=hello
OBJS=hello.o
$(TARGET): $(OBJS)

上記のファイル群を用意したら、インポート前に行う下準備は 2つ。
  • モジュール名を決める
  • 不要なファイルを消す
モジュール名とは、最上位のディレクトリ名のことを指す。ここでは hello としておこう。そして CVS で管理したくない不要なファイルを削除する。この例では、make すると生成される実行ファイル hello、オブジェクトファイル hello.o、エディタのバックアップファイル hello.c~ などは管理対象としない方がよい。そのため、インポート前に不要なファイルを削除しておこう。

準備ができたら、cvs import でインポートする。書式は以下の通り。
% cvs import [モジュール名] [ベンダタグ] [リリースタグ]
ベンダブランチ・イニシャルブランチはとりあえずは気にせず、それぞれ vendor・initial としておこう。必ずカレントディレクトリを hello/ に変更してからインポートすること。
% cd hello/
% cvs import -m "Initial version" hello vendor inital
U hello/hello.c
U hello/Makefile

No conflicts created by this import

「No conflicts created by this import」と表示されれば正常にインポートできたということである。インポートが完了したら、リポジトリ内にどのように格納されているのか確認しておこう。
% find ~/cvsroot/hello
/home/68user/cvsroot/hello
/home/68user/cvsroot/hello/hello.c,v
/home/68user/cvsroot/hello/Makefile,v
ディレクトリ名はそのままだが、ファイル名の末尾には「,v」が付加されている。これが CVS が管理しているファイルの印である。

チェックアウト
リポジトリ内のファイルを取得したり編集したりするには、まずチェックアウトを行わなければならない。まず、CVS の作業場所を決めておこう。ここでは ~/work/ とする。~/work/ に移動して
% cvs checkout [モジュール名]
とすることでチェックアウトが行える。
% mkdir ~/work
% cd ~/work
% cvs checkout hello
cvs checkout: Updating hello
U hello/Makefile
U hello/hello.c
チェックアウトしたディレクトリのファイル構成を確認しよう。
% find hello/ -print
hello/
hello/CVS
hello/CVS/Root
hello/CVS/Repository
hello/CVS/Entries
hello/Makefile
hello/hello.c
チェックアウトしたディレクトリ内には、必ず「CVS」というディレクトリが作成され、その下には Root・Repository・Entiries というファイルがある。各ファイルの内容は以下の通りである。
hello/CVS/Root … リポジトリの場所
/home/68user/cvsroot/
hello/CVS/Repository … この作業場所が対応するリポジトリ内のディレクトリのパス
hello
hello/CVS/Entries … この作業場所で管理しているファイル・ディレクトリ
/Makefile/1.1.1.1/Sun Jul 24 06:54:10 2005//
/hello/1.1.1.1/Sun Jul 24 06:54:10 2005//
/hello.c/1.1.1.1/Sun Jul 24 06:54:10 2005//
これらは CVS 管理用ファイルなので削除してはならないし、内容を改編してはならない。

差分表示 (diff)
チェックアウトしたファイルは、エディタなどを使って自由に修正してよい。

修正中は cvs diff を使って、どの部分を修正したのかを確認しよう。以下は hello.c をエディタで修正した後に cvs diff で差分を表示する例である。
% cvs diff
RCS file: /home/68user/cvsroot/hello/hello.c,v
retrieving revision 1.1.1.1
diff -r1.1.1.1 hello.c
3,4c3,4
< main(){
<     printf("Hello, world.\n");
---
> main(int argc, char *argv[]){
>     printf("This is a sample program of cvs\n");
当ページ管理人は声を大にしていいたいのだが、CVS が威力を発揮するのはここである。エディタの操作ミスやなどで意図せぬ修正を行ってしまった場合でも、cvs diff を行うことでミスに気づくことができる。また、テストのために一時的に変更した行の戻し忘れもここで見付けられる。コミット前には必ず cvs diff を使うようにしよう。

cvs diff には多くのオプションが指定できるが、ほとんどは diff コマンドと共通である。最低限、-u で Unified Diff 形式の差分表示ができることを覚えておくとよい。
% cvs diff -u
RCS file: /home/68user/cvsroot/hello/hello.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 hello.c
--- hello.c     24 Jul 2005 06:54:10 -0000      1.1.1.1
+++ hello.c     25 Jul 2005 13:58:08 -0000
@@ -1,5 +1,5 @@
 #include <stdio.h>

-main(){
-    printf("Hello, world.\n");
+main(int argc, char *argv[]){
+    printf("This is a sample program of cvs\n");
 }

コミット (commit)
ファイルの修正が完了したら、コミットを行ってリポジトリに反映する。
% cvs commit hello.c
とすると vi や Emacs などのエディタが起動するので、コミットログの入力を行う。
■ (←カーソル位置)
CVS: ----------------------------------------------------------------------
CVS: Enter Log. Lines beginning with `CVS:' are removed automatically
CVS:
CVS: Committing in .
CVS:
CVS: Modified Files:
CVS: hello.c
CVS: ----------------------------------------------------------------------
以下のように修正理由や修正概要を記入する。
hoge 値の自動補正機能は今回の開発で削除する予定だったが、
これを削除すると fuga 値に影響が及ぶことが発覚したため、
削除を取り止める (仕様変更)。
CVS: ----------------------------------------------------------------------
CVS: Enter Log. Lines beginning with `CVS:' are removed automatically
(以下略)
「CVS:」から始まる行は無視されるので、そのまま残しておけばよい (削除してもよいが、意味がない)。記入したら内容を保存してエディタを終了する (vi なら :wq、Emacs なら C-x C-s C-x C-c)。すると、
Checking in hello.c;
/home/68user/cvsroot/hello/hello.c,v <-- hello.c
new revision: 1.2; previous revision: 1.1
done
というふうにコミットが行われる。hello/hello.c のリビジョンが 1.1 から 1.2 に上がったことがわかる。コミット時に使用するエディタは、環境変数 EDITOR や環境変数 CVSEDITOR で指定が可能である。

もし cvs commit してエディタが起動した後にコミットをやめたくなった場合は、コミットログ内容を空にして保存し、エディタを終了する。すると
Log message unchanged or not specified
a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
Action: (continue)
と、「ログメッセージが指定されていないがどうする?」と聞いてくる。ここで a (abort) をタイプすればコミットされない。もし e (edit) とすれば再度エディタが起動し、c (continue) とすれば「*** empty log message ***」というログでコミットが実行される。

いちいちエディタが起動するのが面倒ならば、
% cvs commit -m 'コミットメッセージ'
と、サブコマンド commit の -m オプションでコマンドラインからコミットログを指定することもできる。

一度コミットした後にコミットログを変更するには、サブコマンド admin に -m オプションを付けることで可能である。
% cvs admin -m1.4:"ほげほげ" hello.c
⇒ hello.c のリビジョン 1.4 のコミットログを「ほげほげ」に変更

ファイル追加
ファイルを追加するには cvs add を使用する。
% cd hello
% echo hoge > newfile.txt
⇒ 適当なファイルを新規作成
% cvs add newfile.txt
cvs add: scheduling file `newfile.txt' for addition
cvs add: use 'cvs commit' to add this file permanently
⇒ 「newfile.txt を追加予定ファイルとして登録した。ほんとに追加したいなら cvs commit してね」と言っている。
cvs add しただけではまだリポジトリにはファイルが追加されていない。確認のため、cvs status で状態を確認しよう (cvs status 自体の説明は後述)。
% cvs status newfile.txt
===================================================================
File: newfile.txt       Status: Locally Added (★注目)

   Working revision:    New file!
   Repository revision: No revision control file
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)
「Status: Locally Added」となっているので、手元の作業場所に追加予定ファイルとして登録されただけで、リポジトリには反映されていないことがわかる。cvs commit でコミットを行うと、リポジトリに反映される (cvs commit すると例のごとくエディタが起動するので、コミットログを記入すればよい)。

cvs add した後に、ファイル追加を取り止めたくなった場合は
% rm newfile.txt
⇒ まずファイル自体を削除 (一時的に mv で別のファイル名に変えてもよい)
% cvs remove newfile.txt
⇒ cvs remove で追加予定ファイル一覧から除外する
とする。ファイル自体を削除したくなければ、一時的に mv で別のファイル名に変えておけばよい。

なお、バイナリファイルの場合は cvs add に -kb オプションを付けること。
% cvs add -kb newimage.jpg
-kb についての詳細は CVS トピック編を参照のこと。

ファイル削除
一度リポジトリに追加したファイルの削除は、cvs remove で行える。
% cd hello
% rm newfile.txt
⇒ まずファイル自体を削除 (一時的に mv で別のファイル名に変えてもよい)
% cvs remove newfile.txt
cvs remove: scheduling `newfile.txt' for removal
cvs remove: use 'cvs commit' to remove this file permanently
⇒ 削除予定ファイル一覧に追加された
この段階ではまだリポジトリに反映されていない。cvs add と同様に、コミットすることで実際にファイルは削除される。なお、ファイル削除といっても修正履歴は全て残るし、いつでもファイルは復活できる。実際に行われることは、リポジトリに「Attic」というディレクトリが作成され、そこに移動されるだけである。
% find ~/cvsroot/hello
/home/68user/cvsroot/hello
/home/68user/cvsroot/hello/Attic (★ここ)
/home/68user/cvsroot/hello/Attic/newfile.txt (★ここ)
/home/68user/cvsroot/hello/hello.c,v
/home/68user/cvsroot/hello/Makefile,v

cvs remove で削除したファイルを元に戻すには、cvs add すればよい。まず、復活させたい newfile.txt を用意する。削除した時点と同じファイルでもよいし、内容を変えたければ変えてもよい。例えば newfile.txt の履歴が
  • リビジョン 1.1 … 新規作成
  • リビジョン 1.2 … 内容修正
  • リビジョン 1.3 … 削除
となっている場合は、
% cd hello
% cvs update -p -r 1.2 newfile.txt > newfile.txt
とするとリビジョン 1.2 の newfile.txt が入手できる。ファイルが用意できたら cvs add する。
% cvs add newfile.txt
cvs add: re-adding file newfile.txt (in place of dead revision 1.2)
cvs add: use 'cvs commit' to add this file permanently
⇒ 復活予定ファイル一覧に追加された
後はコミットすれば元通りになる。

ディレクトリ追加
ディレクトリの追加は、ファイル追加と同様に cvs add を使用する。
% cd hello
% mkdir newdir
⇒ 適当なディレクトリを作成
% cvs add newdir
Directory /home/68user/cvsroot/hello/newdir added to the repository
ファイル追加の場合は cvs add・cvs commit という二段階を踏む必要があったが、ディレクトリの追加は cvs add すると即座にリポジトリに反映されることに注意しよう。

ディレクトリ削除
一度 add したディレクトリを削除することは、できない。良く言えば「仕様」、悪く言えば「CVS の欠点」である。ただし、リポジトリを直接いじるという裏技はある。上記の newdir ディレクトリ追加の例では、
/home/68user/cvsroot/hello/newdir/
というディレクトリが作成されているので、これを直接 rmdir すればよい。ただし、そのディレクトリを既にチェックアウトした人がいたら、エラーとなる。また、newdir/ の下に既にファイルを追加していた場合は、そのファイルの履歴は全て消えてしまう。当ページ管理人が直接リポジトリのディレクトリを rmdir するのは、以下の条件を全て満たすときである。
  • そのディレクトリを誰もチェックアウトしていない
  • 削除したいディレクトリの下にファイルを置いたことがない

状態表示 (status)
作業場所のファイルの状態を表示するには cvs status を使う。
% cvs status
===================================================================
File: Makefile          Status: Up-to-date

   Working revision:    1.1.1.1 Sun Jul 24 06:54:10 2005
   Repository revision: 1.1.1.1 /home/68user/cvsroot/hello/Makefile,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)

===================================================================
File: hello.c           Status: Locally Modified

   Working revision:    1.5     Sat Jul 30 14:26:13 2005
   Repository revision: 1.5     /home/68user/cvsroot/hello/hello.c,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)
Makefile がリビジョン 1.1.1.1、hello.c が 1.5 であり、Makefile は最新版 (Up-to-date)、hello.c は修正されているがまだコミットされていない (Locally Modified) ことがわかる。

一人で、ひとつの作業場所で作業する場合は、以下のステータスを覚えておけばよい。
Up-to-date 最新版。リポジトリの最新リビジョンと内容が完全に一致している状態
Locally Added ファイルを cvs add したが、まだコミットしていない状態
Locally Removed ファイルを cvs remove したが、まだコミットしていない状態
Locally Modified 作業場所のファイルを修正したが、まだコミットしていない状態
全てのステータスや、Sitcky Tag・Sticky Date・Sticky Options については CVS トピック編を参照。

CVSチュートリアル応用編へ続く。