Subversionリポジトリと連携できるgit-svn

 「Gitを使いたいが、中央リポジトリにはSubversionを使わざるを得ない」という場合も多いだろう。そのような状況で便利なのが、SubversionリポジトリとGitリポジトリの橋渡しをする「git-svn」である。git-svnを利用することで、SubversionリポジトリとGitのローカルリポジトリを同期させることが可能だ。本記事では、このgit-svnの活用方法を紹介する。

git-svnのアーキテクチャ

 Gitの大きな特徴として、分散型アーキテクチャがある。分散型アーキテクチャでは、コミットはローカルのリポジトリに対して行い、ソースコードの同期はそれぞれの開発者間が持つローカルリポジトリ同士で変更点をやりとりすることで行う。もちろん公開リポジトリを利用したソースコードの同期も可能であり、柔軟な開発体制を取れるのが長所である。

 しかし、一方でGitは非常に多数のコマンドがあり、CVSやSubversionといった旧来のバージョン管理システムとは異なるアーキテクチャであるため、移行が難しいという問題もある。また、Windows環境での利用についても、現状ではまだ難がある。そのため、バージョン管理システムをSubversionからGitに切り替える、というのはそう簡単ではない。そこで活用したいのが、GitリポジトリとSubversionリポジトリとの橋渡しを行う「git-svn」コマンドである。git-svnを利用すると、SubversionリポジトリからGitリポジトリにファイルをチェックアウトしたり、GitリポジトリからSubversionリポジトリにコミットを行うことができるようになる(図1)。

図1 git-svnの利用イメージ
図1 git-svnの利用イメージ

Subversionリポジトリからローカルリポジトリを作る

 Subversionリポジトリを元にGitのローカルリポジトリを作るには、「git svn clone <リポジトリ>」コマンドを利用する。

たとえば、「svn+ssh://hoge@svn.sourceforge.jp/svnroot/hogehoge/trunk/hogehoge」というSubversionリポジトリを元にローカルリポジトリを作成するには、次のようにする。
$ git svn clone svn+ssh://hoge@svn.sourceforge.jp/svnroot/hogehoge/trunk/hogehoge

 この場合、カレントディレクトリに「hogehoge」というディレクトリが作成され、そこがローカルリポジトリとなる。なお、デフォルトではSubversionリポジトリのすべての変更履歴がダウンロードされるため、多くの変更履歴を持つSubversionリポジトリの場合はリポジトリの作成に非常に時間がかかる場合があるので注意してほしい。

 また、「-s」オプションを付けてgit svn cloneを実行することで、ブランチやタグの情報も含んだローカルリポジトリを作成できる。ただし、-sオプションを利用する場合、Subversionリポジトリ内でブランチが「branches/」以下、タグが「tags/」以下、trunkが「trunk/」以下に作成されている必要がある。もしこれ以外のパスにブランチやタグ、trunkが作成されている場合は、次のようにしてこれらを指定すればよい。

$ git svn clone --trunk=<trunkのパス> --tags=<タグのパス> --branches=<ブランチのパス> <リポジトリURL>

 たとえば、trunkが「svn+ssh://hoge@svn.sourceforge.jp/svnroot/hogehoge/test1」以下、タグが「svn+ssh://hoge@svn.sourceforge.jp/svnroot/hogehoge/tag」以下、ブランチが「svn+ssh://hoge@svn.sourceforge.jp/svnroot/hogehoge/branch」以下に配置されている場合、下記のように指定する。

$ git svn clone --trunk=test1 --tags=tag --branches=branch svn+ssh://hoge@svn.sourceforge.jp/svnroot/hogehoge/

 このようにして作成したGitリポジトリは通常のGitリポジトリとまったく同様に扱え、「git commit」コマンドによるコミットや「git add」コマンドによるファイルの追加、「git rm」や「git mv」コマンドによるファイルの削除や移動などが行える。

ローカルリポジトリにコミットした変更をSubversionリポジトリに送信する

 Subversionでは、「svn commit」コマンドを実行することで、Subversionリポジトリに変更点が記録される。いっぽうgit-svnでsvn commitに相当するコマンドが「git svn dcommit」だ。git-svnを利用している場合、「git commit」ではローカルリポジトリへのコミットのみが行われるので、適切なタイミングでgit svn dcommitを実行し、変更点をSubversionに反映させる必要がある。

$ git svn dcommit

Subversionリポジトリとローカルリポジトリを同期させる

 ローカルリポジトリを最新のSubversionリポジトリと同期させるには、「git svn rebase」コマンドを使用する。これはSubversionの「svn update」に相当するものだ。

$ git svn rebase

特定のブランチを対象に作業を行う

 特定のブランチを対象にソースを取得したりコミットを行う場合、Subversionではそのブランチをチェックアウトして修正を行いコミットする、という流れだった。一方git-svnの場合も、基本的な流れは同じである。Subversionリポジトリ上にあるブランチは、「git branch -r」コマンドで確認できる。

$ git branch -r
  0.9.3-b1
  0.9.3-b2
  tags/0.9.3
  tags/0.9.3-b1
  trunk

 git branch -rコマンドで表示されるブランチは「リモートブランチ(Remote branch)」と呼ばれるもので、リモートリポジトリ上(今回の場合はSubversionリポジトリ)に存在するブランチである。いっぽう、ローカルリポジトリ上にあるブランチは「ローカルブランチ」と呼ばれる。リモートブランチは直接チェックアウトすることはできないが、これらを元にローカルブランチを作成することはできる。つまり、これらのブランチに対して作業を行いたい場合は、これらのブランチを元に新たなローカルブランチを作成すればよい。

 たとえば「0.9.3-jp-b2」ブランチに対して作業を行いたい場合、まず「git branch」コマンドを使用してそのブランチを元に新たなローカルブランチを作成する。下記の実行例では、「local-0.9.3-jp-b2」という名前でローカルブランチを作成している。

$ git branch local-0.9.3-b2 0.9.3-b2

 続いてこのローカルブランチをチェックアウトして作業を行えばよい。変更を行ったあとはcommitを実行し、最後にgit svn dcommitを実行すれば、変更点がSubversionリポジトリのブランチに反映される。

$ git checkout local-0.9.3-b2
(作業を行う)
$ git commit
$ git svn dcommit

 また、git-svnにはSubversionリポジトリ上にブランチを作成したり、タグを作成する機能もある。たとえば最新のコミットを元に新たなブランチを作成するには、「git svn branch」を実行すればよい。

$ git svn branch <作成するブランチ名>

 タグを作成する場合も同様で、「git svn tag」コマンドを実行すればよい。

$ git svn tag <タグ名>

 なお、Subversionリポジトリへのアクセスに「svn+ssh」プロトコルを使用している場合、git-svnでのブランチ/タグ作成がうまく行かない場合があるようだ。この場合は面倒だがsvnコマンドなどでブランチ/タグを作成するようにしよう。

コラム:SubversionのタグとGitのタグ

 Subversionではタグやブランチはともにディレクトリとして扱われるが、Gitではタグとブランチは明確に別のものとして扱われている。そのため、SubversionのタグはGitではブランチ相当のものとして扱われる。