読者です 読者をやめる 読者になる 読者になる

GitとSubversionを併用する

仕事ではSubversion(以下、svn)を使っているのだが、これをgitに置き換えたい。
とはいえ、いきなり全体をgitに移行するのはキツそうなので、以下のようなプロセスを踏もうと思う。

(1) 自分の環境だけgitを使えるようにする(中央リポジトリsvn
(2) 他のメンバー(数名規模)もgitを使えるようにする(中央リポジトリsvn
(3) 中央リポジトリsvnからgitに変える

このエントリでは上記(1)の経緯を書きとめておく。

現状

・以下のように中央にsvnリポジトリが存在していて、各人がそこからチェックアウトしている
・各人はチェックアウトした「svn作業コピー」から「作業用ディレクトリ」にコピーしている(cpやrsyncで)
・各人の「作業用ディレクトリ」のhtdocsはdev環境としてブラウザから閲覧可能
・各人の「svn作業コピー」と「作業用ディレクトリ」は一致しない(バージョン管理しないファイルが沢山ある)
・各人の「svn作業コピー」と「作業用ディレクトリ」の差分管理がとにかく大変な状況

自分の環境だけでもgitにおきかえたい。方法として以下の3つが思いついたので、それぞれ試してみた。
最終的に「(C) git-svnを使う」ことになったのだが、折角なのでそこまでの経緯を記録しておく。

(A) 「svn作業コピー」を「gitリモートリポジトリ」として使う

以下のようにsvn作業コピーをgitリモートリポジトリ(bareではないワーキングツリーを持つリポジトリ)にして、gitローカルリポジトリからpull/pushする形を考えた。

結果: 不採用
理由: gitのリモートリポジトリは基本的にbareリポジトリであることが推奨されるため。


# svnリポジトリからチェックアウトしてsvn作業コピーを作る
$ svn checkout [svnリポジトリ] [svn作業コピー]

# svn作業コピーをgit管理下におく(gitリモートリポジトリを兼任させる)
$ cd [svn作業コピーのトップ]
$ git init

# svnの管理下から.gitと.gitignoreを除去
# ※設定用のエディタにはvimを使用した
# ※参考: http://log.xinu.jp/2011-07-25-1.html
$ export svn_EDITOR="vim"
$ svn propedit svn:ignore ./
.git
.gitignore

# 確認
$ svn status
$ svn status --no-ignore

# gitの管理下から.svnを除去
$ vim .gitignore
.svn

# 確認
$ git status

# gitにコミットする
$ git add .
$ git commit -m 'init'

# 作業ディレクトリ(gitローカルリポジトリ)に移動し
# svn作業コピー(gitリモートリポジトリ)からcloneする
$ cd [作業ディレクトリ|gitローカルリポジトリ]
$ git clone [svn作業コピー|gitリモートリポジトリ]

# なんらかのファイルに変更を加えた後、pushする
$ git add .
$ git commit -m 'test'
$ git push

# エラーが出る!
(略)
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error: 
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error: 
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
(略)

(B) 「svn作業コピー」を「gitローカルリポジトリ」として使う

以下のようにsvn作業コピーをgitローカルリポジトリとして使う構成を考えた。
gitリモートリポジトリを別途用意して、それを中間地点としてpull/pushするような構成。

結果: 不採用
理由: 一応できたが、何度もpushやpullをする必要があって面倒。また複雑なのでミスも多くなりそう。


# >>> ここから
$ svn checkout file:hoge fuge
$ cd [svn作業コピーのトップ]
$ git init
$ export svn_EDITOR="vim"
$ svn propedit svn:ignore ./
.git
.gitignore
$ vim .gitignore
.svn
$ git add .
$ git commit -m 'init'
# <<< ここまでは1.と同じ

# gitのbareリポジトリを作る
$ mkdir [git_bareリポジトリの]
$ cd [git_bareリポジトリ]
$ git clone --bare [svn作業コピー]

# svn作業コピーに移動し、作成したgitのbareリポジトリをgitリモートリポジトリに設定する
$ cd [svn作業コピー]
$ git remote add [リモートリポジトリ名] [git_bareリポジトリ]

# 作業用のディレクトリにcloneする
$ cd [作業用ディレクトリ]
$ git clone [git_bareリポジトリ]

# 作業用ディレクトリでなんらかのファイルに変更を加えた後、pushする
$ git add .
$ git commit -m 'test'
$ git push

# svn作業コピーでgit pull
$ cd [svn作業コピー]
$ git pull

# svnの状態を確認
$ svn status -u

(C) git-svnを使う

結果として定石通りにこれを採用した。

自分の環境での問題は、git管理下におきたくないファイルが異常に沢山あること。
そこで.gitignoreファイルをかなり丁寧に指定した。
.gitignoreの指定方法にについてはこちらのエントリにまとめた。

また、以下のサイトを参考にして作業した。
git svn cloneをやるときは--prefix svn/をつけるべき - DQNEO起業日記
Git - Git と Subversion

# 現在の作業用ディレクトリをいったん退避
$ mv [作業用ディレクトリ] [旧作業ディレクトリ]

# 新しい作業用ディレクトリを作成し、git管理下に
$ mkdir [新作業用ディレクトリ]
$ cd [新作業用ディレクトリ]
$ git init

# git-svnがインストールされているか確認。なければインストール
$ git svn --version

# subversionのリポジトリを取り込む
# <注意!>過去のコミット数が多いと、死ぬほど時間がかかる場合がある(数日かかる場合もあるらしい)ので注意
# 自分の環境では、1000コミットくらいあるリポジトリが15分くらいだった
$ git svn clone -s --prefix svn/ [svnリポジトリ(trunkはつけない)] [clone後ディレクトリ名]

# svnリポジトリの情報確認
# svnリポジトリのログ確認
$ git svn info
$ git svn log

# .gitignoreを細かく指定
$ vim .gitignore
色々な設定

# 旧作業用ディレクトリを新作業用ディレクトリに上書き
$ cp -R [旧作業用ディレクトリの内容] [新作業用ディレクトリ]

# 確認
git status

実運用

こちらのブログに掲載されている内容が大変参考になりました。
git-svnを使うときのベストプラクティス - Life goes on
git-svnの使い方を覚えた - idesaku blog

今後

各人がローカル環境でgitに慣れたらリモートリポジトリ自体をsvnからgitに移管しよう