howto/cvs †
一行メモ †
すごく単純なCVSの使い方で、頻繁に使う操作 †
チェックアウトした後、trunkのみを使ってゆく場合。
次のように、ファイル更新を繰り返す。
$ cvs update -d
# -d はリポジトリに存在し、作業用にないディレクトリをコピーする
# 代わりに -Pにすると、空ディレクトリは削除される
# 表示されるメッセージ
# C コンフリクトしていた
# P リポジトリのファイルに作業用のファイルを合わせて修正した
# U リポジトリから作業用ディレクトリにファイルをコピーした
# M 作業用ファイルは、リポジトリのファイルと比べて修正されている事を示している
$ cvs diff -u ファイル名
# リポジトリと作業用のファイルのdiffをとる
$ emacs
# コンフリクトしたファイルには、<<<<などの印により衝突部分がファイル中に
# 埋め込まれるので、これをエディタで編集(merge)する。
$ cvs ci -m "message"
利用環境 †
~/.cvsignore (CVSのチェック対象から外す) †
*.x
*.exe
*.o
~/.cvswrappers (CVSでバイナリ扱いとする) †
*.xyz -k 'b'
*.jpg -k 'b'
*.gif -k 'b'
*.png -k 'b'
*.tif -k 'b'
*.doc -k 'b'
*.xls -k 'b'
*.ppt -k 'b'
*.tar -k 'b'
*.tgz -k 'b'
*.gz -k 'b'
*.Z -k 'b'
~/.cvsrc (自動で付けるオプション) †
diff -u
update -d -P
cvs -q
~/.cvsrepos (リポジトリーの例) †
# For use this repository (rep directory which contains
# various suites),
# $ source ~/.cvsrepos
export CVSROOT=~/rep
#export CVSROOT=:ext:okazaki@hoge.ac.jp:/home/okazaki/rep
export CVS_RSH=ssh
export CVSWRAPPERS=~/.cvswrappers
リポジトリ(作成、追加、移動、削除) †
リポジトリを作る †
mkdir ~/rep
cvs -d ~/rep init # リポジトリを作って初期化。
# このディレクトリ(rep)に、複数のプロジェクト
# を入れることができる。従って、一つのサーバに
# ひとつリポジトリがあれば十分である。
chmod -R go-rwx ~/rep # 必要ならセキュリティのためパーミッションを変更
リポジトリにプロジェクトを追加する †
PAIIIディレクトリの内容を、PAIIIというプロジェクト名で追加(~/rep/PAIIIが作成される)する場合、
source ~/.cvsrepos # 又は export CVSROOT=$HOME/rep
cd ~/samba_shared/ExtraDoc_ringo/PAIII # 追加したいディレクトリの中に移動
cvs import -m "Prog A III" PAIII okazaki initial # 追加
# カレントディレクトリの内容が、~/repに、PAIII(プロジェクト名)の
# ディレクトリ名で保存される
rm -rf ~/samba_shared/ExtraDoc_ringo/PAIII # 不要である
importオプションの説明
cvs import -m "start project" proj vender initial
ログメッセージ プロジェ ベンダ リリース
クト名 タグ タグ
projが、repディレクトリ内のディレクトリ名や、チェックアウトするときの
プロジェクト名になる。
リポジトリの移動 †
サーバにあるリポジトリのディレクトリ(例えば~/rep)を丸ごと、移動させればよい。
ただし、クライアントの方はcheckoutし直す。同一サーバ内でリポジトリが移動した場合
でも、パスが変わるのでクライアントの方のcheckoutし直しは必要である。
タグを設定する †
cvs -q tag Release-1999_05_01
メジャーバージョンを上げる †
(予め、作業用コピーは全てコミットしていること)
cvs commit -m "upping major version number" -r 2.0
プロジェクトヒストリを見る †
cvs annotate [file] # ファイルの各行について、誰がいつ作ったかが分かる
cvs history -e -a [file] # ファイルに対して行った操作の履歴が分かる
パッケージ化をする †
プロジェクトmyprojについて、myproj-1.0ディレクトリにcheckoutする。この時、CVSディレクトリを作らない。
cvs -q export -r Release_1_0 -d myproj-1.0 myproj # -rでタグを指定
or
cvs -q export -D tomorrow -d myproj-1.0 myproj # -Dで時間(この例ではtomorrow)を指定
後は、tar cvf myproj-1.0.tar myproj-1.0 などをする。
作業用コピーを削除する †
cvs release -d myproj # myprojはチェックアウトしたディレクトリであるとする
(rm -r myproj と同様である)
リポジトリを削除する †
1) 作業用ディレクトリをすべて削除する。
2) リポジトリ内の該当するプロジェクトのディレクトリを丸ごと削除する。
3) 次の2点はやらなくても問題は起こらない。
$CVSROOT/CVSROOT/val-tags から該当するプロジェクトの行を削除
$CVSROOT/CVSROOT/history から該当するプロジェクトの行を削除
基本的な操作 †
作業コピーをチェックアウトする †
$ cvs checkout [-d 指定するディレクトリに保存] [-r タグ] proj
projディレクトリ(プロジェクト名)が作られて、その中にリポジトリからのファイルが置かれる
コミットする †
$ cvs commit -m "log message" [files]
ファイルを追加する †
$ cvs add newfile.c
$ cvs commit -m "add newfile.c" [newfile.c]
[newfile.c]は省略化。この場合は全ファイルを対象にしてcommitが行われる。
ファイルがバイナリであるときは、cvs add -kb files のように行う。間違ってテキストでadd した場合は、
いったんcommitし、その後、そのファイルを削除、commitする。それからバイナリでaddし直す。
追加するファイルと同じファイル名のファイルがリポジトリにあった場合、作業用のファイルがリポジトリに
updateの形では追加されない。予め作業用の方のファイルを消しておき、update後、そのファイルを修正する。
ディレクトリを追加する *1 †
$ mkdir c-subdir
$ cvs add c-subdir
$ cvs ci -m "log"
$ cvs update -P #空のディレクトリがある場合、作業用コピー上のものは削除される
ディレクトリ内のファイル追加は、そのディレクトリに移って「ファイルを追加する」を行う
ファイルを削除する †
$ rm newfile.c
$ cvs remove newfile.c
$ cvs ci -m "removed newfile.c" newfile.c
ファイル名を変更する †
$ mv oldname newname
$ cvs remove oldname
$ cvs add newname
$ cvs ci -m "renamed oldname to newname" oldname newname
ディレクトリを削除する †
まずディレクトリ内のファイルをすべて削除する
$ pwd
dir/
$ cvs update -P #空のディレクトリがある場合、作業用コピー上のものは削除される
ディレクトリ名を変更する †
$ mkdir newdir
$ cvs add newdir
$ mv olddir/* newdir
$ cd olddir
$ cvs rm foo.c bar.txt #olddirにあったファイル
$ cd ../newdir
$ cvs add foo.c bar.txt
$ cd ..
$ cvs ci -m "moved foo.c and bar.txt from olddir to newdir"
$ cvs update -P
バイナリファイルを追加する †
$ cvs add -kb files #キーワード展開を中止、および改行を変換を中止
$ cvs add -kk files #キーワード展開を中止
cvs update -kk や cvs update -kb をしたソースをコミットすると、それのオプションは以後ずっと残る。
コマンドの省略形 †
checkout = co
commit = ci
update = up
その他 †
● CVSログからGNUスタイルのChangeLogを生成する ( cvs2cl.pl )
$ cvs2cl.pl -r -b -t [--stdout] [files]
-h ヘルプ表示
-r リビジョン番号を含める
-b ブランチ名を含める
-t タグ名を含める
--stdout ChangeLogファイルではなく、標準出力に出す。
● INFOマニュアル $ info cvs
● キーワード展開
$Revision$
$Log$
● (クライアントとしての)リポジトリの設定、簡単な使用例
cvsのグローバルオプション、-d :pserver:jrandom@cvs.foobar.com:/usr/local/cvs
又は
環境変数、CVSROOT=:pserver:jrandom@cvs.foobar.com:/usr/local/cvs
ローカルなリポジトリの場合は、CVSROOT=/usr/local/cvs
リモートな場所のリポジトリの場所へのアクセス方式として、
pserver, ext(rsh,ssh; シェルは環境変数 CVS_RSH=ssh で指定),
kserver(Kerberos), gserver(GSSAPI)方式がある。
リモートなcvsサーバへのログイン、ログアウト cvs login ; cvs logout
● CVSROOT管理用ディレクトリのチェックアウト
$ cvs co CVSROOT
● 特定の時刻のスナップショットを入手する
$ cvs -q update -D "1999-04-19 23:59:59 GMT"
● Sticky特性を削除する(作業用コピーは最新のリビジョンになる)
$ cvs -q update -A
● ブランチを作る
$ cvs -q tag -b Release-1999_05_01-branch
● 作業コピーの内容を調べる
$ cd myproj
$ cvs -q [-n] update [files] # -nを付けた場合、作業用コピーのファイルは更新されない
$ cvs -Q diff [-u] [files]
△● リビジョン番号を調べる
$ cvs [-Q] status [files]
△● ログを調べる
$ cvs log [files]
△● 内容の変更を調べる
$ cvs diff -u -r 1.3 -r 1.4 [files]
リビジョン番号
リビジョン番号
$ cvs diff
全ファイルを対象に、リポジトリとの差分をとる
● hello.cの古いリビジョン番号1.3のファイルを取り出し、新たにhello.cとして保存する。
(古いファイルを復活させる)
$ cvs -Q update -p -r 1.3 hello.c > hello.c
● hello.cにリビジョン番号1.4から1.3への変更パッチをhello.cに当てる。
$ cvs update -j 1.4 -j 1.3 hello.c
● ブランチからトランクへ変更をマージする
$ cvs -q update -A
$ cvs -q diff -u -r Release-1999_05_01-branch #ブランチの最新との差分を調べる
$ cvs -q update -j Release-1999_05_01-branch #ブランチのルートからブランチの最新まで の差分を
#現在の作業用コピーに反映させる
( cvs -q update -j Release-1999_05_01-branch-fix-number-1 -j Release-1999_05_01-branch )
( #ブランチのタグ Release-1999_05_01-branch-fix-number-1 から )
( #ブランチの最新までの差分を現在の作業用コピーに反 映させる )
$ cvs -q update
$ cvs -q ci -m "merged from branch Release-1999_05_01-branch"
● CVSのwatch機能 pp.142-153
● コミット後にログメッセージを変更する
$ cvs admin -m 1.7:"Truncate four-digit years to two in input." date.c
● CVSで、サーバや、anonymousの運用のための設定 (未チェック、試していない)
(1) /etc/groupに、cvsを追加
cvs:*:105:kfogel,sussman,jimb,noel,lefty,fitz,craig,anonymous,jrandom
(2) リポジトリの初期化、オーナーグループ、アクセス権を設定 (ローカルにて)
local$ cvs -d /usr/local/newrepos init
local$ cd /usr/local/newrepos
local$ chgrp -R cvs . #ディレクトリにsetgidを実行しておくと、新規作成のファイルやディレクトリは
#親のものが引き継がれる(BSD,Linux)
local$ chmod ug+rwx . CVSROOT
(3) pserver方式を用いる時
/etc/servicesに cvspserver 2401/tcp を追加し、
/etc/initd.confに、
cvspserver stream tcp nowait root /usr/local/bin/cvs cvs --allow-root=/usr/local/newrepos pserver
or
cvspserver stream tcp nowait root /usr/sbin/tcpd /usr/local/bin/cvs --allow-root=/usr/local/newrepos pserver
(tcpwrappersを使うシステムの場合)
を追加し、
kill -HUP "inetdのPID"
する。
(4) CVSROOT/passwd を作る
passwdファイルの形式は、「CVSユーザ名:暗号化パスワード:システムユーザ名」の繰り返し。
(パスワードはクリアテキストで送られるので、/etc/passwdとは別が良い)
TIPS: cryptout.pl; 暗号化するユーティリティ(p111)
=================================================?
#!/usr/bin/perl
srand (time());
my $randletter = "(int (rand (26)) + (int (rand (1) + .5) % 2 ? 65 : 97))";
my $salt = sprintf ("%c%c", eval $randletter, eval $randletter);
my $plaintext = shift;
my $crypttext = crypt ($plaintext, $salt);
print "${crypttext}";
print "\n";
=================================================
(1') 複数のプロジェクトを扱う場合(p112)、
/etc/passwd にプロジェクト別のcvsユーザを追加
cvs-foo:*:600:600:Public CVS Account for Project foo:/usr/local/cvs:/bin/false
cvs-bar:*:601:601:Public CVS Account for Project bar:/usr/local/cvs:/bin/false
/etc/group にプロジェクト別のcvsグループを追加
cvs-foo:*:600:cvs-foo
cvs-bar:*:601:cvs-bar
(4') CVSROOT/passwd にユーザとプロジェクトの対応を作成
kcunderh:...:cvs-foo
jmankoff:...:cvs-foo
dstone:...:cvs-bar
twp:...:cvs-bar
(他) 読みとり専用ユーザ等を設定
CVSROOT/readers ファイルにユーザ名を含めると、全てのプロジェクトに対して読み取りだけ が行える(p113)
CVSROOT/writers ファイルにユーザ名を含めると、含まれていない全てのpserverユーザは読み 取りだけが行える(p113)
ソースの更新手法 *2 †
「トランクに何度もマージする」手順 †
<<branch:Exotic_Greetings-branch>>
+-----------------+(Exotic_Greetings-1)-------+(Exotic_Greetings-2)...→
| . \ . .\
| . \ . . \
| . \. . \
<<trunk>> | . V . V
---+(Root-of-Exotic_Greetings)----+(merged-Exotic_Greetings)---+(merged-Exotic_Greeti ngs-1)...→
. . . . .
. . . . .
. . . . .
*A**B* *C* *D**E*
<<paさん、yaさん、とその他の人が仕事をしている状況>>
<<トランク>> <<ブランチ>>
pa$ cvs tag Root-of-Exotic_Greetings #ブランチのルート(ブランチポイントタグ)
pa$ cvs tag -b Exotic_Greetings-branch #ブランチを作る
pa$ cvs update -r Exotic_Greetings-branch #作業コピーをブランチにする
pa$ emacs #何か編集
pa$ cvs ci -m "print exotic greetings"
. . . *A* . . .
ya$ emacs #何か編集
ya$ cvs ci -m "some very stable changes indeed"
. . . *B* . . . ★マージする★
ya$ cvs diff -u -r Exotic_Greetings-branch #ブランチのブランチルートからの変更を調べる
#ブランチのタグは常に最新のブランチソースを示す
ya$ cvs update -j Exotic_Greetings-branch #ブランチのブランチルートからの変更をトランクにマージする
(ya$ cvs update #他の人のトランクへの更新を加える、念のためする)
(ya$ emacs #**競合**を編集)
ya$ cvs ci -m "merged from Exotic_Greetings-branch (conflicts resolved)"
ya$ cvs tag merged-Exotic_Greetings
. . . *C* . . .
pa$ cvs tag Exotic_Greetings-1
pa$ emacs #何か編集
pa$ cvs ci -m "print a capitalized greeting"
pa$ cvs -q tag Exotic_Greetings-2
. . . *D* . . .
ya$ emacs #何か編集
ya$ cvs ci -m "Mention new Exotic Greeting features"
. . . *E* . . . ★マージする★(これを何度もする)
ya$ cvs -q diff -u -r Exotic_Greetings-1 -r Exotic_Greetings-branch #ブランチの Exotic_Greetings-1からの変更を調べる
ya$ cvs -q update -j Exotic_Greetings-1 -j Exotic_Greetings-branch #Exotic_Greetings-1から最新までの更新を
#トランクにマージ する
(ya$ cvs -q update)
(ya$ emacs #**競合**を編集)
ya$ cvs -q ci -m "merged again from Exotic_Greetings-1"
ya$ cvs -q tag merged-Exotic_Greetings-1
||何度もすることのまとめ
|| 作業コピーはトランクである。
|| cvs -q diff -u -r "前回マージしたブランチのタグ" -r "ブランチタグ"
|| cvs -q update -j "前回マージしたブランチのタグ" -j "ブランチタグ"
|| cvs -q update
|| 競合を編集
|| cvs -q ci -m "ログメッセージ"
|| cvs -q tag "トランクに付けるマージ後のラベル"
「トランクの変更をブランチにマージする」手順 †
<<branch:Exotic_Greetings-branch>>
+---------------------------------------------+(merged-merged-Exotic_Greetings-1)...→
| . ^
| . /
| . /
<<trunk>> | . /
-------------+------+(merged-Exotic_Greetings-1)--------...→
.
.
.
*A*
<<paさん、yaさん、とその他の人が仕事をしている状況>>
<<トランク>> <<ブランチ>>
ya$ emacs #何か編集
ya$ cvs ci -m "clarify algorithm"
. . . *A* . . .
pa$ cvs -q update -j merged-Exotic_Greetings-1 -j HEAD #merged-Exotic_Greetings-1からトランクの先端
#までの更 新を加える
#HEADはト ランクの先端を示す
(pa$ cvs update #他の人のブランチへの更新を加える、念のためする)
pa$ cvs -q ci -m "merged trunk, from merged-Exotic_Greetings-1 to HEAD"
pa$ cvs -q tag merged-merged-Exotic_Greetings-1
||全般的な注釈
|| Stickyタグが設定されているスナップショットでは、コミットできない。
|| トランク(cvs update -A)、または、ブランチ(cvs update -r ブランチタグ)の先端で、コ ミットをする。
「トビウオ方式のマージ」手順 (簡単な方法) †
<<branch-1>> <<branch-2>>
+-----------| +----------...→|
| \ |. \
| \ |. \
| \ |. \
<<trunk>> | V |. V
----------+----------------+----------------------------...→
.
.
.
*A*
<<paさん、yaさん、とその他の人が仕事をしている状況>>
<<トランク>> <<ブランチ>>
ya$ cvs tag -b branch-1 #ブランチを作る
pa$ cvs checkout -r branch-1 #ブランチを作業コピーとしてチェック アウトする
(pa$ emacs #何かを編集)
pa$ cvs ci -m "committing all uncommitted changes"
(ya$ emacs #何かを編集)
ya$ cvs update -j branch-1
(ya$ emacs #**競合**を編集)
ya$ cvs ci -m "merged from branch-1"
. . . *A* . . .
ya$ cvs tab -b branch-2
pa$ cvs checkout -r branch-1 #ブランチを作業コピーとしてチェック アウトする
||注釈
|| yaさんがマージしている間は、完了するまでブランチの人は完全に待ち状態となる
「サードパーティソースを追跡する」手法 (本家の開発中のソースに、随時手を加えたい状況) †
#VER1.0をリポジトリtheirprojにインポートする。
$ cvs import -m "import theirproj 1.0" theirproj them theirproj_1_0
#theirprojのソースを独自に修正
$ cvs co theirproj
$ cd theirproj
$ emacs #何かを編集
$ cvs update
$ cvs ci -m "changed digestion algorithm; added comment to main"
#VER2.0がリリースされたので、リポジトリtheirprojにインポートする。
$ cvs -import -m "import theirproj 2.0" theirproj them theirproj_2_0
.... #競合した場合
cvs checkout -jthem:yesterday -jthem theirproj #のメッセージ
$ cvs co -j theirproj_1_0 -j theirproj_2_0 #theirproj_1_0の独自の修正をした最新ソース からtheirproj_2_0への
#更新を、theirproj_1_0の独自の修正をした最 新ソースに適用した結果を
#チェックアウトするらしい。以下、競合を解 決してチェックインする。
$ cvs update
$ cvs diff
$ emacs #**競合**を編集
$ cvs update
$ cvs diff
$ cvs ci -m "resolved conflicts with import of 2.0"