subversion不徹底入門
CVSが広く使われるようになってきてますが、CVSにもいろいろ嫌なところが
わかってきています。commitの単位がファイル単位であるとか、ファイルの
移動ができないなどが有名なところでしょう。
そこで、それらを改善したリビジョンコントロールシステムがほしくなって
くるわけです。ずいぶん前から subversion というのがその目標としている
ところからみて有望視されてきてましたが、もうすでにある程度は実用に
なってきているので、それを紹介しておきましょう。
FSIJあたりでも subversionをつかってみようという話があがってきているので
そのうち fsij.org あたりで subversion serviceを提供するかもしれません(?)
では、まずインストールからです。sidならばそのままapt-getで
インストールできます。
ここではいきなりいれるのはコワいという人のために woodyなマシンに
chroot環境にsubversionをいれる方法を紹介します。
まず chroot環境をいれるディレクトリをつくり、そこで debootstrap
を使って初期の環境を作成します。
# mkdir sid-root
# debootstrap sid sid-root
E: Couldn't download libpcap0
あら、だめです。どうも woodyリリース時の debootstrapに
はいっているsidの情報と今のsidの状態がくいちがっているようです。
もう一度全部消して、sidのdebootstrapをダウンロードしてきてその中の
/usr/lib/debootstrap/scriptからsidというdebootstrapのスクリプトを
とってきます。それを debootstrap/sid というファイルにおいておいて
debootstrapすると
# debootstrap sid sid-root http://hp.debian.or.jp/debian debootstrap/sid
I: Base system installed successfully.
これで sid-root以下に sidのchroot環境ができました。chrootコマンドを
使って
# chroot ./sid-chroot
これで sid-chrootの環境にはいることができます。
/etc/apt/sources.listを編集してapt-getでsubversionをインストールします。
# apt-get install subversion
Reading Package Lists...
Building Dependency Tree...
The following extra packages will be installed:
libapr0 libdb4.0 libneon23 libssl0.9.6 libsvn0 libxml2 libxmltok1 patch
zlib1g
The following NEW packages will be installed:
libapr0 libdb4.0 libneon23 libssl0.9.6 libsvn0 libxml2 libxmltok1 patch
subversion zlib1g
0 packages upgraded, 10 newly installed, 0 to remove and 0 not upgraded.
Need to get 3138kB of archives. After unpacking 8505kB will be used.
Do you want to continue? [Y/n] y
さらに subversion-server, subversion-toolsもインストールしておきます。
# apt-get install subversion-server subversion-tools
Reading Package Lists...
Building Dependency Tree...
The following extra packages will be installed:
apache2-common libapache2-dav-svn libswig1.3 mime-support python2.2
python2.2-subversion rcs
The following NEW packages will be installed:
apache2-common libapache2-dav-svn libswig1.3 mime-support python2.2
python2.2-subversion rcs subversion-server subversion-tools
0 packages upgraded, 9 newly installed, 0 to remove and 0 not upgraded.
Need to get 4541kB of archives. After unpacking 18.2MB will be used.
Do you want to continue? [Y/n] y
これでsubversionのコマンドがインストールできました。
リポジトリの作成
まずリポジトリの作成をしてみましょう。これは CVS でいうところの
cvs -d /cvsroot init
に相当する作業です。
subversionのリポジトリを /svn/repos にするとすると次のコマンドで
リポジトリが作成できます。
# svnadmin create /svn/repos
cvsではそのままリポジトリディレクトリを使って作業ができましたが、subversion
では WebDAV を使ってリポジトリにアクセスします。したがってWebDAVで
アクセスできるように apache2 をインストールして、subversionむけの
設定をする必要があります。
これは CVSでいうところの pserverの設定 に相当すると考えていいでしょう。
CVSでは inetd.conf に
cvspserver stream tcp nowait.40 root /usr/sbin/tcpd /usr/sbin/cvs-pserver
という設定をするのに相当するわけです。
まず apache2 をインストールします。
# apt-get install apache2
Reading Package Lists...
Building Dependency Tree...
Package apache2 is a virtual package provided by:
apache2-mpm-worker 2.0.43-1
apache2-mpm-threadpool 2.0.43-1
apache2-mpm-prefork 2.0.43-1
apache2-mpm-perchild 2.0.43-1
You should explicitly select one to install.
E: Package apache2 has no installation candidate
Descriptionをみくらべてみると -prefork がstableっぽいので
これをinstallしておくといいでしょう。
# apt-get install apache2-mpm-prefork
Reading Package Lists...
Building Dependency Tree...
The following NEW packages will be installed:
apache2-mpm-prefork
0 packages upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 200kB of archives. After unpacking 578kB will be used.
Get:1 http://hp.debian.or.jp sid/main apache2-mpm-prefork 2.0.43-1 [200kB]
Fetched 200kB in 0s (663kB/s)
Selecting previously deselected package apache2-mpm-prefork.
(Reading database ... 8741 files and directories currently installed.)
Unpacking apache2-mpm-prefork (from .../apache2-mpm-prefork_2.0.43-1_i386.deb) ...
Setting up apache2-mpm-prefork (2.0.43-1) ...
Starting web server: Apache2(98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
Unable to open logs
invoke-rc.d: initscript apache2, action "start" failed.
dpkg: error processing apache2-mpm-prefork (--configure):
subprocess post-installation script returned error exit status 1
Errors were encountered while processing:
apache2-mpm-prefork
E: Sub-process /usr/bin/dpkg returned an error code (1)
#
woody環境で apache などを動かしていれば、そこで port 80 で apacheが
動いているはずなので、sid chroot環境で動いているapache2の port を
かえておきます。port 番号は /etc/apache2/ports.conf で設定できます。
/etc/apache2/ports.conf:
Listen 80
となっているのを例えば
Listen 2481
とかにします。(2401(pserver)+80(http))
これで dpkg --configure -a をすると unpack 状態のapache2の
設定が最後までおこなわれて installed 状態にすることができます。
# dpkg --configure -a
Setting up apache2-mpm-prefork (2.0.43-1) ...
Starting web server: Apache2.
# dpkg -C
次に subversionむけの設定です。これは
/etc/apache2/mods-available/dav_svn.conf
というファイルで設定します。
例えば以下のようにします。
DAV svn
SVNPath /svn/repos
このファイルは実は /etc/apache2/mods-enable/ からsymlinkされていて
/etc/apache2/apache2.conf で /etc/apache2/mods-enabled/*.{load,conf}を
Include しています。
なお、apache2 processのユーザ (/etc/apache2/apache2.conf の User で
指定されているユーザ。defaultは www-data)の権限でアクセスするので、
リポジトリのownerをそのユーザにしておく必要があります。
# chown -R www-data:www-data /svn/repos
このように設定をかえたら apache2をリスタートしておきます
# /etc/init.d/apache2 restart
ここまでで、このapache2にアクセスしてみましょう。
GET するとこうなります。
# telnet localhost 2481
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /svn/repos/ HTTP/1.0
HTTP/1.1 200 OK
Date: Wed, 20 Nov 2002 15:40:26 GMT
Server: Apache/2.0.43 (Debian GNU/Linux) DAV/2 SVN/0.14.5 (r3566)
ETag: "0//"
Accept-Ranges: bytes
Content-Length: 218
Connection: close
Content-Type: text/html; charset=UTF-8
Revision 0: /
Revision 0: /
Powered by Subversion version 0.14.5 (r3566).
Connection closed by foreign host.
これで、anonymousユーザで/svn/reposにsubversionコマンドで
アクセスできるようになります。本当はちゃんとユーザ認証すべきですが
それについては後述します。
まずsubversion管理下にいれてみましょう。CVSではimportに相当する
作業です。
subversionのコマンドは/usr/bin/svnというコマンドです。
# cd /tmp
# mkdir test
# cd test
# vi test.txt
This is test.
# cd ..
# svn import http://localhost:2481/svn/repos/ test test
こうすると testディレクトリ以下を リポジトリのtest以下に
importすることになります。CVSの時と同じようにimport時の
メッセージを指定していないと $EDITORがたちあがってメッセージを
入力するようにうながされます。
----------------------------------------------------------------
--This line, and those below, will be ignored--
A test
~
~
----------------------------------------------------------------
で、適当にメッセージをいれてエディタを終了するとimportされます。
----------------------------------------------------------------
This is test module.
--This line, and those below, will be ignored--
A test
~
~
----------------------------------------------------------------
Adding test/test.txt
Transmitting file data .
Committed revision 3.
これで test/ 以下が http://localhost:2481/svn/repos の下の test/ 以下に
importされます。
CVSではリポジトリにどういうのがあるのかといったリストをとるのは
基本的には用意されていませんでしたが、subversionではlistというコマンドで
どういうのがあるかを調べることができます。
# svn list http://localhost:2481/svn/repos
test/
このように test というのがあるのがわかります。
ここでimport前の test を test-old にmvしておきましょう。
# mv test test-old
checkoutをする
次にリポジトリから最新の状態をとりだしてきましょう。CVSでいうところの
cvs checkoutに相当する作業です。subversionでもsvn checkoutでおこないます。
# svn checkout http://localhost:2481/svn/repos/test
A test/test.txt
Checked out revision 5.
# cd test
# ls -la
total 16
drwxr-xr-x 3 root root 4096 Nov 20 16:04 .
drwxrwxrwt 4 root root 4096 Nov 20 16:04 ..
drwxr-xr-x 8 root root 4096 Nov 20 16:04 .svn
-rw-r--r-- 1 root root 14 Nov 20 16:04 test.txt
CVSではCVS/というCVSが管理するためのディレクトリが作られていましたが、
subversionでは.svnというディレクトリがつくられていることがわかります。
logをみる
commitした時のログをみるには svn log コマンドを使います。
CVSでいうところの cvs log に相当する作業です。
# svn log
------------------------------------------------------------------------
rev 5: anonymous | 2002-11-20 16:02:15 +0000 (Wed, 20 Nov 2002) | 2 lines
This is test module.
------------------------------------------------------------------------
また現在の手元(Working copy)の状態をみるための svn info というコマンドが
あります。
# svn info
Path:
Url: http://localhost:2481/svn/repos/test
Revision: 5
Node Kind: directory
Schedule: normal
Last Changed Author: anonymous
Last Changed Rev: 5
Last Changed Date: 2002-11-20 16:02:15 +0000 (Wed, 20 Nov 2002)
# svn info test.txt
Path: test.txt
Name: test.txt
Url: http://localhost:2481/svn/repos/test/test.txt
Revision: 5
Node Kind: file
Schedule: normal
Last Changed Author: anonymous
Last Changed Rev: 5
Last Changed Date: 2002-11-20 16:02:15 +0000 (Wed, 20 Nov 2002)
Text Last Updated: 2002-11-20 16:04:48 +0000 (Wed, 20 Nov 2002)
Properties Last Updated: 2002-11-20 16:04:48 +0000 (Wed, 20 Nov 2002)
Checksum: MgrstsrYkQjmx+T9GLUTMQ==
編集して commitしてみよう
まず適当にファイルを編集してみましょう。
# vi test.txt
This is test 2.
で、diffをとってみます。これはCVSでいうところの cvs diffに相当する
作業です。subversionでも svn diffコマンドでdiffがとれます。
# svn diff
Index: test.txt
===================================================================
--- test.txt (revision 5)
+++ test.txt (working copy)
@@ -1 +1 @@
-This is test.
+This is test 2.
diff(1)でつかえるオプションをわたすには -x を使います。
# svn diff -x --show-c-function
CVSでのcvs commitに相当する作業は subversionではsvn commitです。
# svn commit
CVSとおなじようにcommit messageを指定していないと$EDITORがたちあがって
commit messageを入力する必要があります。
----------------------------------------------------------------
--This line, and those below, will be ignored--
M /tmp/test/test.txt
----------------------------------------------------------------
commit messageを入力してエディタを終了するとcommitされます。
----------------------------------------------------------------
test -> test 2
--This line, and those below, will be ignored--
M /tmp/test/test.txt
----------------------------------------------------------------
Sending test.txt
Transmitting file data .
Committed revision 6.
変更点をチェキしてみましょう。svn logを使うと commit logをみることが
できます。
# svn log test.txt
------------------------------------------------------------------------
rev 6: anonymous | 2002-11-20 16:12:00 +0000 (Wed, 20 Nov 2002) | 2 lines
test -> test 2
------------------------------------------------------------------------
rev 5: anonymous | 2002-11-20 16:02:15 +0000 (Wed, 20 Nov 2002) | 2 lines
This is test module.
------------------------------------------------------------------------
svn diff を使うとあるrevisionからの差分をみることもできます。
# svn diff -r 5
Index: test.txt
===================================================================
--- test.txt (revision 5)
+++ test.txt (working copy)
@@ -1 +1 @@
-This is test.
+This is test 2.
CVSになかったファイルの移動など
cvsではファイルの移動は mv しておいて cvs remove、cvs add と
するしかありませんでした。subversionではこの点が改善されていて
svn moveコマンドでファイルの移動ができます。またsvn copyコマンド
を使うとファイルのコピーもできます。
ディレクトリ
subversionではディレクトリも svn mkdirコマンドを使うことで
つくっていくことができます。ディレクトリを削除した時は
svn deleteでリポジトリに反映させることができます。
$Id$とかをいれてみる。
# vi test.txt
This is test 2.
$Id$
# svn commit
# svn log
------------------------------------------------------------------------
rev 7: anonymous | 2002-11-20 16:17:21 +0000 (Wed, 20 Nov 2002) | 2 lines
add $Id$
------------------------------------------------------------------------
rev 6: anonymous | 2002-11-20 16:12:00 +0000 (Wed, 20 Nov 2002) | 2 lines
test -> test 2
------------------------------------------------------------------------
rev 5: anonymous | 2002-11-20 16:02:15 +0000 (Wed, 20 Nov 2002) | 2 lines
This is test module.
------------------------------------------------------------------------
# cat test.txt
This is test 2.
$Id$
あれれ、かわっていませんね。subversionでは、このようなkeyword
おきかえはpropertyを設定しないとおこなわれないことになっています。
propoertyを設定するには、次のように svn:keywords propertyに
おきかえするkeyword(たとえばIdとか)を設定します。
# svn propset svn:keywords "Id" test.txt
property `svn:keywords' set on 'test.txt'
現在設定されているpropertyはsvn proplist, svn propgetでわかります。
# svn proplist test.txt
svn:keywords
# svn propget svn:keywords test.txt
Id
ただ propertyを設定しただけではworking copyでの置きかえはおこなわれません。
# cat test.txt
This is test 2.
$Id$
# vi test.txt
This is test.
$Id$
# svn commit -m 'remove 2'
Sending test.txt
Transmitting file data .
Committed revision 8.
# cat test.txt
This is test.
$Id: test.txt 8 2002-11-20 16:20:53Z anonymous $
なお、一気に propset するには例えばこうします。
% svn propset svn:keywords Id `find . \( -name .svn -prune \) -o -type f -print | xargs grep -l '\$Id:'`
% svn commit
anonymousじゃあれなので認証を
さて、いままでではユーザ認証をまったくしていなかったので
誰が編集してもanonymousが作業したことになってしまいます。
そこでユーザ認証するようにしてみましょう。
詳しくは /etc/apache2/mods-available/dav_svn.conf に
かかれている通りです。
まず passwdファイルを作ります。これはapache2のhtpasswd2
コマンドを使って次のようにつくります。
# htpasswd2 -c /etc/subversion/passwd ukai
New password:
Re-type new password:
Adding password for user ukai
で次のように設定します。
# vi /etc/apache2/mods-available/dav_svn.conf
DAV svn
SVNPath /svn/repos
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/subversion/passwd
Require valid-user
これで /svn/reposに対して GET PROPFIND OPTIONS REPORT 以外の
アクセスをする時に/etc/subversion/passwdに登録されているユーザ
でしかアクセスできないようになります。
設定ファイルをかきかえたらapache2をリスタートします。
# /etc/init.d/apache2 restart
一旦削除してもう一度 checkoutしましょう。
# rm -rf test
# svn checkout http://localhost:2481/svn/repos/test
A test/test.txt
Checked out revision 8.
# cd test
# echo by anonymous >> test.txt
ここで svn commit すると、今度はユーザのパスワードをきいてくるようになります。
# svn commit -m 'add by anonymous'
root's password:
ここで単にリターンを入力すると、usernameとpasswordをきいてきます。
username:
password:
どちらもちゃんと入力しないと以下のように認証エラーでcommitできません。
svn: Authorization failed
svn: Commit failed (details follow):
svn: MKACTIVITY of /svn/repos/!svn/act/aa6787e9-e1af-0310-a675-959a2ab7c54d: authorization failed
次にちゃんと user, passwordを入力してみましょう。
# svn commit -m 'add by anonymous'
root's password:
username: ukai
ukai's password:
Sending test.txt
Transmitting file data .
Committed revision 9.
#
もしくは checkoutの時などに --username, --password で usernameとパスワードを
指定しておくと、localに認証情報をcacheしておくことができます。
(実際は .svn/auth/ に記録されます)
# cd ..
# rm -rf test
# svn checkout --username ukai --password 'xxxxxx' http://localhost:2481/svn/repos/test
A test/test.txt
Checked out revision 9.
# cd test
# vi test.txt
This is test.
$Id: test.txt 9 2002-11-20 16:29:37Z ukai $
by ukai
# svn commit -m 'by ukai'
Sending test.txt
Transmitting file data .
Committed revision 10.
conflictの解消
CVSの時と同じように複数の人が同時に編集していると作業がconflictすることが
あります。
# svn commit -m 'conflict test'
Sending test.txt
svn: Merge conflict during commit
svn: Commit failed (details follow):
svn: Your file 'test.txt' is probably out-of-date.
svn:
The version resource does not correspond to the resource within the transaction. Either the requested version resource is out of date (needs to be updated), or the requested version resource is newer than the transaction root (restart the commit).
# svn update
A memo.txt
CU test.txt
Updated to revision 12.
このように conflictしているものは C がついて表示されます。
# cat test.txt
This is test.
$Id: test.txt 12 2002-11-20 17:41:59Z ukai $
$HeadURL: http://localhost:2481/svn/repos/test/test.txt $
by ukai
<<<<<<< .mine
conflict test?
=======
>>>>>>> .r12
# svn status
C test.txt
? test.txt.54040.00001.mine
? test.txt.54044.00001.r12
? test.txt.54048.00001.r10
# svn info test.txt
Path: test.txt
Name: test.txt
Url: http://localhost:2481/svn/repos/test/test.txt
Revision: 12
Node Kind: file
Schedule: normal
Last Changed Author: ukai
Last Changed Rev: 12
Last Changed Date: 2002-11-20 17:41:59 +0000 (Wed, 20 Nov 2002)
Text Last Updated: 2002-11-20 16:32:17 +0000 (Wed, 20 Nov 2002)
Properties Last Updated: 2002-11-20 17:45:20 +0000 (Wed, 20 Nov 2002)
Checksum: WqeO3OAGcvPBoDoBFf5DOA==
Conflict Previous Base File: test.txt.54048.00001.r10
Conflict Previous Working File: test.txt.54040.00001.mine
Conflict Current Base File: test.txt.54044.00001.r12
ここで次のように conflictを解消することができます。
# cat test.txt
This is test.
$Id: test.txt 12 2002-11-20 17:41:59Z ukai $
$HeadURL: http://localhost:2481/svn/repos/test/test.txt $
by ukai
conflict test ok
# svn resolve test.txt
Resolved conflicted state of test.txt
# svn commit -m 'fix conflict'
Sending test.txt
Transmitting file data .
Committed revision 13.
hostでproxy
woody側のapacheで次のように proxy_moduleを有効にして
NameVirtualHost で virtual hostを設定しておくと、
port番号を気にしないで使えるようにできます。
ここで設定するのはchroot側ではなく、元のwoody側の方です。
LoadModule proxy_module /usr/lib/apache/1.3/libproxy.so
NameVirtualHost 192.47.44.103
ServerName svn.fsij.org
ServerAdmin webmaster@fsij.org
ProxyRequests On
ProxyPass / http://localhost:2481/
ProxyPassReverse / http://localhost:2481/
# /etc/init.d/apache stop
# /etc/inti.d/apache start
branch & tags
CVSではtagコマンドを使ってbranchやtagをつくっていましたが
subversionではsvn copyというコマンドを使うことでbranchや
tagをつくります。これはbranchやtagなどといったものは現状の
コピーをもとに編集していったもの、および現状のコピーと
とらえることができると考えるといいでしょう。
まず、svn copyする前に上位のディレクトリをsvn mkdirコマンドで
作っておく必要があります。
% svn mkdir http://svn.fsij.org/svn/repos/branch
もしつくってないとsvn copyなどをしようとしても
svn: RA layer request failed
svn: PROPFIND of /svn/repos/!svn/bc/393/test: 404 Not Found
svn: Your commit message was left in a temporary file:
svn-commit.62368.00002.tmp
のようなエラーがでます。
例えば trunk/test にあるもののbranchを作るにはたとえば
以下のようにします。
% svn copy http://svn.fsij.org/svn/repos/trunk/test \
http://svn.fsij.org/svn/repos/branch/test
これで現状revisionの trunk/test が branch/test にコピーされます。
このコピーしたものがbranchになり、修正していくことができます。
またコピーした時点を tag をうったものとして考えることもできます。
また、svn switchコマンドをつかって
% svn switch http://svn.fsij.org/svn/repos/branch/test
とするとworking copyは branchでの作業をするようになります。
ちなみに
% svn info
をすると Url: がswtichしたほうにかわっているのがわかります。
mergeする時は svn mergeコマンドを使います。
# svn merge url1[@m] url2[@n]
hooks
CVSでは CVSROOT/loginfo などをつかって、コミット時にlog message
などを関係者にメールしたりしていましたが、subversionでは hooks
を使います。
# cd /svn/repos/hooks
# ls -la
total 40
drwxr-xr-x 2 www-data www-data 4096 Nov 28 18:49 .
drwxr-xr-x 7 www-data www-data 4096 Nov 18 16:29 ..
-rw-r--r-- 1 www-data www-data 1287 Nov 18 16:29 post-commit.tmpl
-rw-r--r-- 1 www-data www-data 1375 Nov 18 16:29 post-revprop-change.tmpl
-rw-r--r-- 1 www-data www-data 1640 Nov 18 16:29 pre-commit.tmpl
-rw-r--r-- 1 www-data www-data 1870 Nov 18 16:29 pre-revprop-change.tmpl
-rw-r--r-- 1 www-data www-data 98 Nov 18 16:29 read-sentinels.tmpl
-rw-r--r-- 1 www-data www-data 1377 Nov 18 16:29 start-commit.tmpl
-rw-r--r-- 1 www-data www-data 100 Nov 18 16:29 write-sentinels.tmpl
.tmplというのはサンプルでこの.tmplをのぞいたファイル名にすると実際に
使われるようになります。一番よく使う例としてはcommit logをメールすることで
しょう。これは 例えば 次のような hooks/post-commit で実現できます。
#!/usr/bin/ruby
REPOS=ARGV[0]
REV=ARGV[1].to_i
fromaddr='svn@example.com'
toaddr='svn-committers@example.com'
svnauthor=%x{svnlook #{REPOS} rev #{REV} author}.chomp!
svndate=%x{svnlook #{REPOS} rev #{REV} date}.chomp!
svnchanged=%x{svnlook #{REPOS} rev #{REV} changed}.chomp!
svnlog=%x{svnlook #{REPOS} rev #{REV} log}.chomp!
svndiff=%x{svnlook #{REPOS} rev #{REV} diff}.chomp!
#commit-email.pl "$REPOS" "$REV" toaddr
require 'net/smtp'
Net::SMTP.start( 'localhost', 25 ) {|smtp|
smtp.send_mail < /svn/dump/`date +%Y-%m-%d` 2>/dev/null
CVSからの以降
subversionにはcvs2svnというコマンドが用意されています。
これを使うとcvsのrepositoryからsubversionのrepositoryに
変換することができます。
cvs2svn -s /svn/respo /var/lib/cvs/moge
これで HEAD(trunk)が trunk/moge に変換されます。
他に branchesやtagsなどがブランチ、タグ用に作成されます。
annotate?
CVSにはcvs annotateコマンドで各行がどのrevisionで最後に
変更されたのかを簡単に調べることができますが、これが
subversion にはまだありません。svn 1.0以降に実装される予定です。
最後に
/usr/share/doc/subversion/book/book.html に詳しく書かれているので
それを見ればokでしょう。