2016-02-22T19:42:55+09:00
svn2git でエラーが発生するとレポジトリを問題となるリビジョンだけ省いて Git に移行した
svn2git で、Subversion レボジトリを Git に移行しようとしいたところ、特定のリビジョンを処理している所でエラーが発生して svn2git が完了しない。
r3963 = f335d195f7687cce1c7c3f1a316f7c0ae686b0e7 (refs/remotes/svn/tags/Release_2_2_1) M FileTableController.m M History.rtf A QuickDMG.xcodeproj/tkurita.mode1v3 M QuickDMG.xcodeproj/project.pbxproj M QuickDMG.xcodeproj/tkurita.pbxuser
なんで、こんなエラーが発生するのかも分からんし、回避策をかなり頑張って探したけど見つからない。
過去のコードがそんなに大事とも思わないので、レボジトリの移行をあきらめてもいいのだけど、シャクなので Git の勉強と思って、web を検索しまくり、頭を抱えてのたうち回り、無駄なことしているのではという自己嫌悪に悩まされながら、いろいろ考えてみた。
考えついた唯一の方法は、エラーが発生するリビジョンを避けて、Git レボジトリに変換し、Git に移行してから、そのレボジトリをつなげる事。大まかな手順は、次の通り。
次に細かく実行コマンドも含めて紹介する。
今、リビジョン 3963 でエラーが発生するので、その前後のコミットを別々のレボジトリとして、svn2git する。すなわち、
# r3962までを svn2git $project=project1; mkdir base-repo; cd base-repo svn2git ${SVNREPOS} --authors ../authors.txt \ --trunk /${project}/trunk \ --tags /${project}/tags \ --branches /${project}/branches \ --revision 0:3962
# r3964以降を svn2git $project=project1; mkdir repo3964; cd repo3964 svn2git ${SVNREPOS} --authors ../authors.txt \ --trunk /${project}/trunk \ --tags /${project}/tags \ --branches /${project}/branches \ --revision 3964:HEAD
こうして、エラーが起きるリビジョンを除いて、base-repo と repo3964 ができた。base-repo に repo3964 を取り込む。
cd base-repo git remote add repo3964 ../repo3964 git fetch repo3964 git fetch --tags repo3964 # これを忘れると、repo3964 に含まれるタグが失われる。
取り込んだ repo3964 のコミット群を rebase によって、base-repo の master の後ろに引っ付ける。
git checkout repo3964/master git rebase master
rebase でコンフリクトが発生したら、コンフリクトしたファイルを修正して、add する必要がある。今の場合、git check --theirs で marge されている側のファイルを選択するべき。次のようなシェルスクリプトで一気にコンフリクトを解消できる。
for f in `git ls-files -u | cut -f 2 | sort -u`;do git checkout --theirs $f; git add $f done
コンフリクトを解消したら、rebase を続ける。
git rebase --continue
rebase が完了すると、base-repo の master と repo3964 の master の歴史がつながる。
ここで repository の状態を確認すると、元 repo3964/master から取り込んだコミット郡は master から生えている名無しのブランチになっていると思われる。
$ git status HEAD detached from repo3964/master $ git branch * (HEAD detached from repo3964/master) master
master を最新のコミットまで移動させて HEAD と master を一致させる必要がある。そのために、master に名無しブランチを merge する。ブランチに名前が無いと処理に困るので、一時的な名前を付ける。
git branch repo3964
master に戻り、ブランチ repo3964 をマージする。
git checkout master git marge repo3964
最後に、一時的なブランチ名を消す。
git branch --delete repo3964
これで、できる限り Subversion から Git へ変更履歴を移せたと思う。
いや〜、こんな事で来ちゃうなんて、Git はすげーなと思う。一方で、Subversion のできるようにしかできな優しい世界も懐かしく。悩みは、確実に Subversion を使っているときの方が少なかった。
誰かのお役に立てますように。