Subversion+svkでらくらく分散リポジトリ

第1回Subversionを使おう

Subversionのセットアップから、基本的な操作方法を説明します。

Subversion概要

ソースコードのバージョン管理システムは、ソフトウェアの開発の中でもっとも重要なツールです。チームで開発を行なうときにソースコード管理システムは必須のツールの一つですが、ソースコードだけでなく様々なフィアルも管理できます。単にチームとしての利用だけでなく、個人のツールとしても威力を発揮します。筆者も、個人でバージョン管理システムを導入して、原稿やサーバの設定ファイルなどのドキュメントの管理をしています。

バージョン管理システムとして、以前はCVSが多くのプロジェクトで利用されていました。しかし、CVSは履歴を保持したままでのファイルの移動ができないなどの問題もありました。SubversionはCVSが抱えていた問題を解決するために開発されました。現在では、多くのプロジェクトでSubversionが利用され、CVSからSubversionに移行したプロジェクトも多々あります。SourceForgeでも、CVSと同様にSubversionも利用することができます。

Subversionの利点の一つに、履歴を保持したままファイルやディレクトリの移動や削除が行えることがあります。プロジェクトの初期段階では、ファイルやディレクトリ構成が定まらないまま開始することが多いです。CVSでは、ディレクトリやファイル名を変更(削除と追加)すると履歴が失われてしまいます。Subversionではディレクトリやファイル名を変更しても履歴が保持されるので、プロジェクトの成長にあわせてディレクトリ構成を柔軟に変更できます。

利点の2つ目として、複数のファイルをまとめてコミットすることで、ファイルのセット(複数のファイル)に対して一つのリビジョンが割り振られることが挙げられます。コミットとは、ローカルで編集した内容をサーバのリポジトリに反映することです。リポジトリとは、バージョン管理システムのサーバ上にデータ(ファイル)をためておく場所のことです。バージョン管理用のデータベースと考えてください。ソースコードをコミットするときに、複数のファイルのセットで初めて意味を持つ変更があります。そのような場合、古いリビジョンに戻すときに複数のファイルを同時に戻さないとソフトウェアが正しく動作せず、コンパイルできないケースもあります。CVSではリビジョンを個々のファイルに対して割り当てるため、古いリビジョンに戻す作業は煩雑になります。Subversionでは、リポジトリ全体に対して指定したリビジョンを指定するだけです。また、リビジョン間の差分を確認する場合も、CVSでは個々のファイルに対して差分を確認する必要がありますが、Subversionではリポジトリ全体に対して確認するだけで、リビジョン間で変更があったファイルの差分を全て表示できます。

利点の3つ目として、ネットワーク負荷の軽減があげられます。現在のリビジョンとローカルでの変更分の差分を表示する場合、CVSでは差分を表示するたびにネットワーク経由でローカルでの変更の差分を確認します。Subversionでは、作業用のファイルとは別に、リポジトリの最新バージョンのファイルをローカルに保持(キャッシュ)して、差分の表示はキャッシュに対して行うため、ネットワークやSubversionの負荷が軽減され、高速に表示できます。ただし、古いリビジョンとの差分比較をネットワーク経由で行うのはCVSと同様です。また、ローカルにキャッシュを持つため、単純に実ファイル容量の2倍の容量が必要になります。

また、CVSでは独自のプロトコルか、SSH経由でしかCVSサーバにアクセスできませんが、SubversionはHTTPやHTTPSでのアクセスが可能です。ファイアウォールなど企業内のネットワークからセキュリティポリシを変更することなく外部のSubversionのリポジトリにアクセスできます。

Subversionの動作概念図
画像

Subversionの開発当初は、コマンドラインツールしかなく、CVSに見劣りするところがありました。Subversionが普及するにつれて、TortoiseSVN(Windowsのエクスプローラを拡張したSubversionクライアント)や、Subclipse(EclipseのSubversionクライアント)など、グラフィカルなSubversionクライアントが開発され、周辺環境もCVSと同じかそれ以上に充実しています。

また、Subversionサーバも以前は、LinuxなどのUNIXやUNIXライクなOS上でしか動作しませんでしたが、現在ではWindowsへのインストーラが提供されるなど、サーバ運用の敷居も下がってきています。

Subversionインストールとサーバセットアップ

Subversionのインストールは、Subversionの配布サイトから、使用するサーバのOSに対応したバイナリパッケージを入手してインストールします。Windowsであれば、インストーラを使ってインストールします。Unix系のOSであれば、RPMなどシステムのパッケージ管理を利用して簡単にインストールできます。以下ではUbuntu Linuxを例に説明します。

コンソールから次のコマンドを実行します。

$ sudo aptitude install subversion

これでSubversionサーバを専用サーバで動かすためのソフトウェアとクライアント一式がインストールされます。インストールには、コマンドラインからではなく、Synapticを使用することもできます。ソースコードからビルド、インストールもきますが、ここでは割愛します。

インストールが終了すると、Subversionの管理コマンドが使用できる状態になっています。次にSubversionのリポジトリを作成します。リポジトリを作成するときは、Subversionの管理ツールのsvnadminコマンドを使います。リポジトリを/tmp/myrepositoryに作成する場合は、次のコマンドを実行します。

$ svnadmin create /tmp/myrepository

Subversionのユーザ管理は、リポジトリのディレクトリの設定ファイルで設定します。/tmp/myrepository/conf/svnserve.confを開いて、次の行を変更します。各行の#以降はコメントとみなされます。ここでは、ユーザ認証にpasswdファイルを使用する、という意味になります。

変更前:
# password-db = passwd
変更後:
password-db = passwd

次に同じディレクトリにあるpasswdファイルを編集します。[users]の行の下に次の形式でユーザとパスワードを指定します。

ユーザ名 = パスワード

一行に一人のユーザを指定します。スペースは無視されます。テスト用のユーザ「test」をパスワード「testpasswd」で指定する場合は、次のようになります。

test = testpasswd

これで、サーバを動かすための設定が終わりました。次に実際にサーバを動作させます。コマンドラインから次のコマンドを実行します。

$ svnserve -d --foreground -r /tmp/myrepository

Subversionの専用サーバはsvnserveで起動します。ここでは、-dでデーモンとして起動するように指定しています。デーモン以外にもinetd経由で起動する場合の-iというオプションもあります。オプションで--foregroundを指定しない場合は、バックグラウンドプロセスになります。-rで先ほど作成したリポジトリへのパスを指定します。--pid-fileでpidファイルを作成できます。

サーバが起動したので、サーバにアクセスしてテストしてみます。svnserveが動作しているコンソールとは別のコンソールを立ち上げて、myrepositoryをチェックアウトします。

$ svn checkout svn://localhost/ test

コンソールに「Checked out revision 0.」と表示されて、カレントディレクトリにtestというディレクトリができていれば成功です。

Subversionのサーバは専用サーバとしても動作できますが、sshのトンネリングと組み合わせることで、ネットワーク上をセキュアに通信できます。また、次回紹介するApacheなどのHTTPサーバと組み合わせることで、柔軟なユーザ認証のシステムの構築やファイアウォールへの対応ができるようになります。筆者の社内でもApacheをフロントエンドにして、HTTP/HTTPSで運用しています。

Subversionの基本操作

既に述べたように、SubversionはCVSの後継としてCVSの欠点を補うために開発されました。そのため、Subversionのコマンドの多くはCVSのコマンドと似ています。ここでは、日常的に筆者がよく使う機能を中心に基本的な操作を説明します。詳細は、SubversionのマニュアルSubversionによるバージョン管理を参照してください。

チェックアウト

プロジェクトを開始するとまず、Subversionのリポジトリからローカルの作業ディレクトリにリポジトリをコピー(チェックアウト)します。ここではtestと言う名前でチェックアウトします。

$ svn checkout svn://localhost/ test

プロジェクトのディレクトリ構成

これでリポジトリ全体がチェックアウトできました。次に、基本となるディレクトリを作成します。CVSと違いSubversionでは、ブランチやタグはシステムとしては存在しません。ディレクトリの運用ルールとして、タグやブランチを区別する必要があります。この点はCVSと大きく異なるところで、CVSユーザの多くが混乱します。慣例的に次のようなディレクトリ構成にすることが多いです。

 + Subversionルートディレクトリ
   +- trunk
   +- branches
      +- 各ブランチのディレクトリ
   +- tags
      +- 各ブランチのディレクトリ

チェックアウトしたディレクトリに移動して作業コピーにtrunk、branches、tagsディレクトリを作成します。

$ mkdir trunk
$ mkdir branches
$ mkdir tags

コミット

次にディレクトリを作成したら、作成したディレクトリをサーバにコミットします。まずは、追加したディレクトリをSubversionに追加予告します。

$ svn add trunk branches tags

次に実際にサーバに反映(コミット)します。

$ svn commit -m "start project"

「-m "start project"」はログメッセージになります。このオプションを指定しないと、デフォルトのエディタが立ち上がり、ログの入力を促されます。CVSと違い、Subversionにはログインコマンドがありません。コミットするときなど認証が必要になると、コマンド実行時にユーザIDとパスワードの入力を促されます。一度入力すると、以降はそのユーザIDとパスワードを使って自動的に認証します。

プロジェクトが開始され、ファイルを追加する場合も、同様の操作になります。trunkにreadme.txtを追加してみます。

$ cd trunk
$ echo "Read me first" > readme.txt
$ svn add readme.txt
$ svn commit readme.txt

commitコマンドに明示的にファイル名、ディレクトリ名を指定すると、そのファイル、ディレクトリだけがコミットされます。また、複数のファイル、ディレクトリを指定すれば、一度に複数のファイル、ディレクトリをコミットします。複数のファイル、ディレクトリをまとめてコミットすると、それらを一つのセットとしてリビジョンが割り振られます。

$ echo "GPL" > LICENSE
$ svn add LICENSE
$ svn commit readme.txt LICENSE

削除

ファイルやディレクトリを間違ってコミットしたリ、使用しなくなったファイルやディレクトリなどを削除した場合、deleteコマンドを実行します。例えばtrunkにobsolete.txtがあり、そのファイルを削除する場合は、次のように実行します。

$ cd trunk
$ svn delete obsolete.txt
$ svn commit

deleteを行なうと、そのディレクトリに対して変更が加えられたことになり、最後にそのディレクトリをcommitする必要があります。

更新と競合の解消

チームで開発していると、他の人もリポジトリに対してコミットします。自分の作業ディレクトリを最新にするために、updateコマンドを実行します。

$ svn update

updateを実行すると、時々作業リポジトリの内容を最新のリビジョンに更新できないケースがあります。つまり、コンフリクト(衝突)が起きたケースです。衝突が起きると、⁠ファイル名.mine⁠⁠、⁠ファイル名.rOLDREV⁠⁠、⁠ファイル名.rNEWREV」と言うファイルができます。readme.txtに衝突が起きると、readme.txt、readme.txt.mine、readme.txt.r2, readme.txt.r3というファイルができます。

この場合、手動でコンフリクトを解消する必要があります。コンフリクトを解消するには、下記の方法のいずれかを行ないます。

  • 手動でコンフリクトがおきたファイルをマージ
  • 作業ファイルを「ファイル名.mine⁠⁠、⁠ファイル名.rOLDREV⁠⁠、⁠ファイル名.rNEWREV」のいずれかで上書き
  • ローカルの変更を捨てて最新のリビジョンのファイルを使用

手動でマージする場合、作業ファイルには次のようにマーカがセットされています。

::

 Read me first.
 <<<<<<< .mine
 これは、私の変更点です。
 =======
 これは、サーバの変更点です。
 >>>>>>> .r3
 ここは変更されていません。

「<<<<<<< .mine」から「=======」までが自分の作業ファイルの内容です。⁠=======」から「>>>>>>> .r2」までがサーバ上のファイルの内容です。エディタでそれぞれの内容を確認しながらマージします。

作業ファイルに上書きする場合は、単純に「copy ファイル名.mine ファイル名」とします。

マージした場合も作業ファイルに上書きした場合も修正後に

$ svn resolved readme.txt

として、コンフリクトを解消します。

ローカルの変更を捨てる場合は、次のコマンドを実行します。

$ svn revert readme.txt

revertを実行する場合は、resolveコマンドを実行する必要はありません。以上でコンフリクトの処置は終わりです。

ログの閲覧

コミットしたときのログを取得する場合は、次のコマンドを実行します。

$ svn log readme.txt

ファイル名を指定しない場合は、現在のディレクトリのファイル全体のログが出力されます。リビジョンを指定してログを出力する場合は、⁠-r リビジョン番号」オプションを指定します。

$ svn log -r 2 readme.txt

差分表示

リビジョン間でファイルの変更点を知るためにdiffコマンドを使います。作業コピーの変更点を確認する場合は、

$ svn diff readme.txt

とします。古いリビジョンとの差分を確認する場合は、logコマンドと同様に「-r リビジョン番号」オプションを指定します。

$ svn diff -r 2 readme.txt

また、リビジョン間の差分を確認する場合は、⁠-r」の引数と してリビジョン番号を二つ、コロンで区切って指定します。

$ svn diff -r 2:3 readme.txt

コピーとタグ・ブランチの作成

最後に、ブランチやタグを作成するときには、ディレクトリをコピーします。Subversionのコピーは、サーバ上ではUnixのハードリンクのようにリンク情報だけを持っています。そのため、ディレクトリをコピーしても、サーバ上ではほとんどディスクを消費しません。trunkの最新リビジョンに対してタグを作成する場合は次のようになります。

$ svn copy svn://localhost/trunk svn://localhost/tags/release-1.0

svn://localhost/trunkはSubversionの開発用の最新リビジョンで、コピー元のディレクトリです。このディレクトリをsvn://localhost/branches/release-1.0にコピーしています。

Subversionのちょっと便利なTips

ソフトウェアの開発では、プロジェクトのビルド途中で中間ファイルなどが大量に生成されることがあります。例えば、Javaのプロジェクトではclassファイルが作られます。また、Pythonのプロジェクトではpycファイルやpyoファイルが自動的に作られます。通常はこれらのファイルをバージョン管理の対象から除外する必要があります。バージョン管理の対象から除外するには、ホームディレクトリの.subversion/configファイルを編集します。miscellanyセクションのglobal-ignoreにスペース区切りで「*.class *.pyc」を指定します。

global-ignores = *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store *.class *.pyc *.pyo

この設定を行なうと、Subversionからチェックアウトしたすべての作業コピーでバージョン管理の対象から外れます。

リポジトリのディレクトリ単位で除外ファイルを指定する場合は、propeditコマンドを使ってディレクトリの属性を変更します。

$ svn propedit svn:ignore .

このコマンドを実行するとエディタが立ち上がります。エディタから除外するファイルのパターンを改行区切りで入力後、保存して終了します。classファイルとpyc、pyoファイルを除外する場合は次のようになります。

*.class
*.pyc
*.pyo

Subversionでは、ファイルの属性をリポジトリで管理します。例えば、実行属性のあるファイルをコミットすると、バージョン管理下のファイルに対しても実行属性が付与されます。しかし、Windowsで追加したりする場合などは、実行属性が付与されないことがあります。この場合、次のコマンドを実行することでファイルに属性を追加できます。

$ svn propadd svn:executable 1 myfile.sh

Subversionへコミットしたタイミングで変更内容をチームにメール送信するなどの処理を行いたいことがあります。Subversionでは、コミット、ファイルのロック・アンロック、属性の変更の前後をフックして処理を行えます。コミットメールを送信する場合は、Subversionのサーバのリポジトリのディレクトリ(ここでは/tmp/myrepository)のhooksディレクトリに移動します。このディレクトリにpost-commit.templというファイルがあるので、これをpost-commitに変更して実行属性を与えます。このファイルはシェルスクリプトになっています。

$ cd /tmp/myrepository/hooks
$ cp post-commit.templ post-commit
$ chmod +x post-commit

次にこのファイルをエディタで開いて、次のように記述します。

REPOS="$1"
REV="$2"
export PATH=/usr/share/subversion/hook-scripts/:$PATH
commit-email.pl "$REPOS" "$REV" [email protected]

これで、コミット時に自動的にコミットメールが送信されます。

SubclipseによるEclipseからの操作

ここまでにコマンドラインからのSubversionの操作を説明してきました。SubversionのクライアントはコマンドラインからだけでなくGUIによる直感的な操作が可能です。TortoiseSVN(TortoiseSVN)という、Windowsのシェルに統合されたツールがあります。また、Javaのプロジェクトで一般的な開発環境のEclipseでは、Subclipseというプラグインモジュールで連携できます。

Subsclipseをつかうには、まず、Eclipseの「ヘルプ⁠⁠-⁠ソフトウェア更新⁠⁠-⁠検索とインストール」を選択します。⁠インストールする新しい機能を探す」オプションを選択して「次へ」をクリックします。表示された画面で「新しいリモートサイト」を押し、URLに次のURLを指定します。名前は「Subclipse」のように管理しやすい名前を指定します図1⁠。

図1 ⁠リモートサイト」の編集画面
図1:「リモートサイト」の編集画面

ウィザードに従ってインストールを行なうと、インストール可能なプラグインが2種類表示されます。⁠Subversion Plugin」にチェックを入れてインストールします図2⁠。

図2 ⁠Subclipseプラグイン」を選択
図2:「Subclipseプラグイン」を選択

インストール後、Eclipseを再起動して、Subversionインスペクタを開きます図3⁠。

図3 Subversionインスペクタを開く
図3:Subversionインスペクタを開く

URLにsvn://localhost/を指定図4すると、Subversion管理下のディレクトリ、ファイルが一覧されます。trunkを選択して右クリックし、⁠チェックアウト」すると、Eclipseのプロジェクトとしてチェックアウトできます。

図4 新しいリポジトリを追加
図4:新しいリポジトリを追加

リソースインスペクタなどで、ディレクトリやファイルを右クリック図5すると、⁠チーム」「比較⁠⁠、⁠置換」メニューにSubversionの管理に必要な項目が表示され、ここから更新やコミットなどを行えます。

図5 EclipseのプロジェクトからSubversionの管理メニューを表示
図5:EclipseのプロジェクトからSubversionの管理メニューを表示

おすすめ記事

記事・ニュース一覧