CVS
This content is not available in your language yet.
動いてるプログラムに手を加える前に元のソースファイルをコピーして「~.bak」というファイルを作った。今までにそんな経験はないでしょうか。そういったファイルはほとんどの場合少しも活用されずに埋もれてしまう運命にあります。
CVSを使えばこういう状況を劇的に改善することが出来ます。
CVS(Concurrent Versions System)とはバージョン管理システムの一つで、ファイルの変更情報を管理するソフトウェアです。その管理下に入ったファイルは、任意の時点での内容を取り出したり、いつどんな変更が加えられたかを調べたりといったことが出来ます。
CVS以外のバージョン管理システムとしてはMicrosoft Visual SourceSafeやSubversionが有名ですが、動作するプラットフォームや実績を考えるとCVSが頭一つ抜き出ています。CVSで管理されているオープンソースソフトウェアも数多く、習得しておいて損をするということはないと思います。
CVSを使うにはいくつかのやり方がありますが、ここでは一番応用の利くcvsコマンドを使う方法を取り上げます。
またコマンドのオプションの意味をすべて説明していくと非常に長くなってしまうため必要最低限のものだけを解説します。
CVSの基礎知識
Section titled “CVSの基礎知識”実際に利用する前に、その概念を把握しておくと理解しやすいでしょう。特徴的なキーワードを通して解説します。
:リポジトリ:履歴情報を管理するために、CVS は全てのファイルとディレクトリをリポジトリと呼ばれるところに保存します。
:ワーキング(作業)コピー:リポジトリに情報を保存するといいましたがユーザーは直接リポジトリを触るということはありません。編集を始める前にリポジトリから作業用にファイルをコピーしてきてそのコピーに対して作業を行い、作業が終わったら変更した内容をリポジトリに反映するという形をとります。そのコピーの事をワーキングコピーと呼びます。
:チェックアウト:リポジトリからコピーを取ってくる作業をチェックアウトといいます。
:コミット:ワーキングコピーでの作業内容をリポジトリに反映させる作業をコミットといいます。
CVSの基本的な使い方
Section titled “CVSの基本的な使い方”コマンドの導入と初期設定
Section titled “コマンドの導入と初期設定”Linuxならば多くの場合標準でインストールされていると思いますが、Windowsでは自分で導入する必要があります。
ここではCygwinのCVSパッケージを利用することをおすすめします。http://www.cygwin.com/からsetup.exeを落としてきてウィザードに従って進めるだけなので、ここでは特にインストールの仕方には触れません。
コマンドのインストールが終わったらcvsコマンドを便利に使うために設定ファイルを用意します。
以下のテキストを~/.cvsrcとして保存してください。
cvs -z5 -qdiff -ucheckout -Pupdate -d -Pstatus -vリポジトリを作成する
Section titled “リポジトリを作成する”環境が整ったら早速使ってみましょう。一番最初に行うのはリポジトリの作成です。
シェルで以下のコマンドを実行してください(「$」はプロンプトの開始を意味しているだけなので実際には打たないでください)。
$ cvs -d ~/cvsroot initこれでホームディレクトリ下にcvsrootディレクトリがリポジトリとして作成されました。
ファイルを登録する
Section titled “ファイルを登録する”管理したいファイルを登録する作業を行います。例として、以下のようなディレクトリ構成のfooプロジェクトを登録するものとします。
~`-- foo/ |-- Main.java `-- Sub.javaMain.javaの内容は次のようになっています。
public class Main {
public static void main(String[] args) { System.out.println("Helo, World!"); return; }
}Sub.javaの内容は次のようになっています。
public class Sub {
}まずプロジェクトのディレクトリに移って
$ cd ~/fooimportします。
$ cvs -d ~/cvsroot import -m "test" foo somebody foo_v_0N foo/Main.javaN foo/Sub.java
No conflicts created by this importfooのところにはプロジェクト名(CVSではモジュール名といいます)を、somebodyのところにはあなたの
名前をいれてください。
これで登録が終わりました。既存のプロジェクトディレクトリはいらないので削除しておきます。
$ cd$ rm -rf fooチェックアウトする
Section titled “チェックアウトする”概念の項で説明したように、実際にファイルを編集するにはワーキングコピーを作成する必要があります。
$ cd$ ls -Fcvsroot/
$ cvs -d ~/cvsroot checkout fooU foo/Main.javaU foo/Sub.java
$ ls -Fcvsroot/ foo/fooディレクトリが作成されたことが確認できました。ディレクトリの中身も見てみます。
$ cd foo$ ls -FCVS/ Main.java Sub.javaMain.java、Sub.javaがちゃんとあります。CVSディレクトリはCVSが使うので触らないようにしてください。
ファイルの編集~リポジトリへの登録の流れ
Section titled “ファイルの編集~リポジトリへの登録の流れ”ここまでで準備が終わりました。後は普段通りファイルを編集してください。
update(up)コマンド
Section titled “update(up)コマンド”長時間編集を続けていると自分がどのファイルに変更を加えたか分からなくなってくることがあります。
そういうときにはupdateコマンドを使うと便利です。なお、これ以降のcvsコマンドは必ずワーキングコピーのディレクトリ内で実行する必要があります。
$ cd ~/foo$ cvs updateまだ変更していないので、当然ですが何も出力されません。
この例ではMain.javaに出力する文字列が間違っているというミスがあるのでそれを直すことにします。
修正が終わったらコンパイル、実行して意図通りの挙動になっているか確認します。
$ javac Main.java$ java MainHello, World!問題ないようですね。ここでもう一回updateコマンドを使います。毎回updateと打つのは面倒なのでupという略で実行しましょう。
$ cvs upM Main.java? Main.class一行目はMain.javaが変更された(Modified)ということを示しています。手を加えていないSub.javaの情報は出力されません。
二行目はCVSの管理下にないMain.classというファイルがあるということを示しています。Main.classはMain.javaから生成できるのでバージョン管理する必要はありません。無視して次のステップへ進みます。
diff(di)コマンド
Section titled “diff(di)コマンド”updateコマンドでどのファイルを変更したのかは分かりました。しかしどういった変更をしたのかまでは分かりません。
それを調べるために使われるのがdiffコマンドです。
$ cvs diffIndex: Main.java===================================================================RCS file: /home/somebody/cvsroot/foo/Main.java,vretrieving revision 1.1.1.1diff -u -r1.1.1.1 Main.java--- Main.java 23 Sep 2004 02:51:12 -0000 1.1.1.1+++ Main.java 23 Sep 2004 02:51:46 -0000@@ -1,7 +1,7 @@ public class Main {
public static void main(String[] args) {- System.out.println("Helo, World!");+ System.out.println("Hello, World!"); return; }長いメッセージが出力されましたが、後半を見ればどういう変更が行われたかが分かると思います。
この中でもう一つ注目して欲しいのが
diff -u -r1.1.1.1 Main.javaという行です。これは手元にあるMain.javaと(リポジトリにある)リビジョン1.1.1.1のMain.javaとを比較して
差分を出力せよということを表しています。リビジョンという聞き慣れない単語が出てきましたがこれについては
後で説明します。
commit(ci)コマンド
Section titled “commit(ci)コマンド”さて、編集作業も一段落つきました。これまでの作業内容をリポジトリに反映させる必要がありますが、その作業をコミットといいます(概念の項でも説明しました)。CVSを使わない場合における「編集を行う前にバックアップを取っておく」作業に相当します。
コミットするにはcommitコマンドを使います。
$ cvs commit -m "fixed output message." Main.javaChecking in Main.java;/home/somebody/cvsroot/foo/Main.java,v <-- Main.javanew revision: 1.2; previous revision: 1.1done出力するメッセージを直したというログを含めてコミットを行いました。
出力をよく見るとまたリビジョンという語が出てきたことに気づくと思います。
リビジョンとはファイルの各履歴につく通し番号のようなもので、コミットするたびに増加していきます。これまで編集してきたMain.javaは1.2というリビジョン番号がついたことになります。今後Main.javaをどんなに変更したとしてもリポジトリからリビジョン1.2のMain.javaを持ってくれば、現時点のMain.javaを復元できることになります。
コミットした結果updateコマンドの結果はどのようになったのでしょうか。
$ cvs up? Main.class変更が取り込まれたため、Main.javaのMマークが無くなりました。
これで基本的な流れはつかめたと思います。今後は「ファイルの編集~リポジトリへの登録の流れ」を繰り返し行うことになります。
履歴の活用の仕方
Section titled “履歴の活用の仕方”CVSはため込んだ履歴を効果的に使うことが出来ます。
任意のリビジョンのファイルを手に入れる
Section titled “任意のリビジョンのファイルを手に入れる”ありがちなのは編集を進めるうちに詰まってしまって、とりあえず直前のリビジョンに戻したいというケースでしょう。
こんな時はupdateコマンドに-Cオプションを付けて実行します。
$ cvs upM Main.java? Main.class
$ cvs up -C Main.java(Locally modified Main.java moved to .#Main.java.1.2)U Main.java直前ではなく、もっと古いリビジョンのものが必要なときには-r[リビジョン番号]を付けます。リビジョン1.1のMain.javaが
欲しいときには次のようにします。
$ cvs up -r1.1 Main.javaU Main.java
$ cat Main.javapublic class Main {
public static void main(String[] args) { System.out.println("Helo, World!"); return; }
}過去のある時点でのリビジョン番号を覚えているということはほとんど無いので、普通はログを見て特定することになります。
$ cvs log Main.java
RCS file: /home/somebody/cvsroot/foo/Main.java,vWorking file: Main.javahead: 1.2branch:locks: strictaccess list:symbolic names: foo_v_0: 1.1.1.1 somebody: 1.1.1keyword substitution: kvtotal revisions: 3; selected revisions: 3description:----------------------------revision 1.2date: 2004/09/23 04:23:09; author: somebody; state: Exp; lines: +1 -1fix output message.----------------------------revision 1.1date: 2004/09/23 02:51:12; author: somebody; state: Exp;branches: 1.1.1;Initial revision----------------------------revision 1.1.1.1date: 2004/09/23 02:51:12; author: somebody; state: Exp; lines: +0 -0test=============================================================================このときに役に立つのがコミット時に指定するログメッセージです。分かりやすいログメッセージを残すようにしましょう。
annotate(ann)コマンド
Section titled “annotate(ann)コマンド”annotateコマンドを使うと、ファイルのある箇所が最後に更新されたのがいつかを調べることが出来ます。
$ cvs annotate Main.java
Annotations for Main.java***************1.1 (somebody 23-Sep-04): public class Main {1.1 (somebody 23-Sep-04):1.1 (somebody 23-Sep-04): public static void main(String[] args) {1.2 (somebody 23-Sep-04): System.out.println("Hello, World!");1.1 (somebody 23-Sep-04): return;1.1 (somebody 23-Sep-04): }1.1 (somebody 23-Sep-04):1.1 (somebody 23-Sep-04): }1.1 (somebody 23-Sep-04):このコマンドを使うとソースを調べるのが非常に楽になります。
たとえばリビジョン1.2で更新された行が気になったとしましょう。
ログを見れば(「ログを見る」の項参照)、この行が1.2になって新たに追加されたわけではなくprintlnメソッドに与えられている
引数が変更されたんだろうと推測できます。実際にどんな変更が行われたか見るのも簡単です。
$ cvs di -r1.1 -r1.2 Main.javaIndex: Main.java===================================================================RCS file: /home/somebody/cvsroot/foo/Main.java,vretrieving revision 1.1retrieving revision 1.2diff -u -r1.1 -r1.2--- Main.java 23 Sep 2004 02:51:12 -0000 1.1+++ Main.java 23 Sep 2004 04:23:09 -0000 1.2@@ -1,7 +1,7 @@ public class Main {
public static void main(String[] args) {- System.out.println("Helo, World!");+ System.out.println("Hello, World!"); return; }CVSの少し高度な使い方
Section titled “CVSの少し高度な使い方”.cvsignoreによるファイルの明示的な除外
Section titled “.cvsignoreによるファイルの明示的な除外”$ cvs up? Main.classこれまでMain.classは単純に無視してきましたが、ここでは明示的に除外してみます。
.cvsignoreファイルの作成
Section titled “.cvsignoreファイルの作成”以下の内容で.cvsignoreというファイルを作成してください。
Main.classupdateコマンドを実行します。
$ cvs up? .cvsignoreMain.classに関する情報は表示されなくなり、今度は新しく加えた.cvsignoreが管理下にないファイルだと示されました。
addコマンド
Section titled “addコマンド”.cvsignoreはバージョン管理していく方が良さそうです。リポジトリに新しくファイルを追加するにはaddコマンドを使います。
$ cvs add .cvsignorecvs add: use 'cvs commit' to add this file permanentlyファイルを永久に追加するには「cvs commit」を使えというメッセージが出ていますが、ひとまず置いておいて現時点での状態をupdateコマンドで確認します。
$ cvs upA .cvsignore「?」が「A」に変わり追加待ちとなっています。コミットしてリポジトリに反映します。
$ cvs ci -m "new file." .cvsignoreRCS file: /home/somebody/cvsroot/foo/.cvsignore,vdoneChecking in .cvsignore;/home/somebody/cvsroot/foo/.cvsignore,v <-- .cvsignoreinitial revision: 1.1doneこれで期待通りの結果が得られます。
$ ls -aF./ ../ .cvsignore CVS/ Main.class Main.java Sub.java
$ cvs upところで.cvsignoreで指定するパターンにはワイルドカードが使えます。今後classファイルが増えることも考えられるので、Main.classではなく*.classを指定した方がよいでしょう。
ここに記したのはCVSの機能のごく一部に過ぎず、内容も不正確な部分があります。CVSに興味を持ったら他の資料をあたって勉強することをおすすめします。参考までにいくつか挙げておきます。