git svn cloneして、ファイル編集して、git commitして、git svn dcommitでSubversionサーバに変更を反映させる。Subversionの変更を取ってくるのはgit svn rebaseだ… なんてのがWeb上で探してすぐ見つかる情報ですが、これでは複数人でgitを使う場合の運用ですぐに行き詰まってしまいます。
実用Git
の16章に定石が載っていると聞き、さっそく買って読んでみました。他の章を飛ばして16章だけ読んだせいもあるのか自分の中ではまだうまく消化出来ていません。とりあえず手順だけ書いておきます。
◯前提条件
git svnを行う窓口は1箇所にする。git svnのオプションを変えたり、とってくるリビジョンを変えただけでもコミットオブジェクトは変わってしまう。
◯前準備
git svnを使ってSubversionリポジトリのcloneを作る
% mkdir example-svn.git
% git svn clone –stdlayout –prefix=svn/ http://example.jp/svn-repos/
git bareリポジトリを作る
% mkdir example.git
% cd example.git
% git init –bare –shared=true
git svnリポジトリからmasterとSubversionのブランチをgitのセントラルリポジトリにpushする。
% cd ../example-svn.git
% git push –all ../example.git
% git push ../example.git ‘refs/remotes/svn/*:refs/heads/svn/*’
◯Subversionにマージを書き戻す
% git checkout svn/trunk
% git merge –no-ff new-feature
% git svn dcommit
何度も実用Gitの解説を読んでいるのですが、マージを書き戻すところだけどうにも謎です。多分きちんとリモート追跡を理解できてないのでしょう。この休みにまた時間をとって勉強することにします。
実際にやってみて出来ることは確認したのですが、
- Subversionへの書き戻しを手動でやらないといけない
- Subversionのログに残るメッセージがgit mergeで生成されたものになってしまい、何の変更をしたのかSubversionからはさっぱりわからない
という問題があることも分かりました。
そこで上記でいうexample-svn.gitのフックスクリプトを作成し、example-svn.gitのmasterに変更がpushされたらSubversionに書き戻す処理を自動化してみました。動く気はしているのですが、理解が足りてないせいで、思わぬ問題を引き起こすかもしれませんのでご注意ください。
#!/bin/sh
# checkout svn/trunk
git checkout svn/trunk
# Store git log before merge
log=$(git log last-merged..master --pretty=format:"%h %s" --reverse)
# merge master to svn/trunk, don't commit
git merge --no-ff --no-commit master
# commit with git log message
git commit -a -m "$log"
# push back to svn repository
git svn dcommit
# tag last merged
git tag -d last-merged
git tag last-merged master
◯2010年3月3日追記
テスト環境ではうまく行ったのですが、本番環境でgit->Subversionの自動同期をしてみたところ、ソースファイルが削除される問題が起きてしまいました。
git push, git mergeとかのどこかでうまくいってないのにsvn dcommitまで行われたのが直接の原因ですが、なぜこうなったのかログを見ても原因が分からなかったので自動同期は止めました。
◯2010年3月4日追記
よくよく考えたらsvnのゲートウェイとなるリポジトリのmasterとsvn/trunkは別個の歴史を辿るんですね。なので前にマージされてからの差分を求めるにはsvn/trunk..masterでは駄目ですね。上のスクリプトはなんとなく書き換えてみましたが、gitの理解が足りてないですね。