最近、諸事情あってsubversion
からgit
へプロジェクトの半ばでバージョン管理を変更しました。その際にちょっと変わった形でgit-svn
の運用を行う事になったのでやりかたに関して簡単にログを残しておきます。
プロジェクトを取り巻く事情
今まではSubversion(仮にメインとします)を用いた運用を行っていたのですが、気軽にtrunkに対してコミットする事が出来ない事情がありました。では、メインSubversion上にbranchをたてればいいじゃんという話になるのですが、ブランチすら気軽に切る事が出来ない状態でした。その上、メインのSubversionにコミットすることが可能なのはコミッターだけとなっておりコミッターの負担が増えつつありました。
今までの運用
今まではメインSubversionとは別に **同期しないSubversion(仮にローカルとします)**を別途立てて、なんと手動でメイン<=>ローカル間の同期を取りながら運用を行ってきました。
※破線の部分はVCSによって連携していない部分です。
当然ですがこの運用ははっきり言って色んな無理があり様々な問題が発生しました。
例えば、、、
- メインからローカルへ ファイル単位で取り込みを行う必要があった。
- メインからローカルへ 取り込むタイミングが保証出来なかった。
- メインからローカルへ取り込みを行った際に どの変更を取り込んだかログが紛失してしまう
- メインのブランチが増えた場合に 同期しなければいけないブランチが増える
- ローカルからメインへコミットする際にコミッターがコミットを行うが、 ファイル単位でメール添付で行っておりミスがしやすい。
- 何より色々めんどくさい!!
.. まぁ、正気の沙汰じゃないですね。
git-svnを利用した解決策を探る
まだコミットの粒度が大きい場合は、 コミッターの注意深い対応と開発者の空気を読んだ行動により、この運用でもなんとかなっていました。
しかしながら障害対応なども割り込んでくるため個別に行う必要がありカオスな状況になっていきます。
何よりこんなリスキーな運用を回しきれる訳がありませんし、自分がどこかで間違える自信があります。
そこでgit-svn
を導入する事でローカルのSubversion
をgit
に置き換えて同期させる方法を検討しました。
基本的には、git-svn
を用いた通常のワークフローで問題なかったのですがいくつか問題がありました。
コミッターの制限
メインのSubversionへコミットが可能なのはコミッターのみでそれ以外のユーザがコミットをする事が禁止されています。
コメントの問題
ある特定の書式に従ってコミットコメントを書く必要があり、マージ運用を行った場合に問題が発生する可能性がありました。
gitの習熟度
全員で10名ほどのプロジェクトですが、数名をのぞきgit
の習熟度がとても低い状態でした(というか知らない状態)。その状態でgit
のみではなくgit-svn
を利用出来る状態は危険な状態が予想されました。
というわけで解決策
これらの問題を考慮した上で以下のような方針で行うようにしました。
リポジトリの構成は以下のようになります。
- コミッターのみ
git-svn
を利用する。 - その他の開発者は
git
のみを利用する。 - 開発者はgitの共用リポジトリを参照し、それをcloneして開発を行う。
- 共用リポジトリはコミッターが所有する物とする。
- 共用リポジトリの
master
はメインSubversionのtrunkとなる。 - 共用リポジトリの
svn/
から始まるブランチは、メインSubversionのブランチとなる - master及びsvn/のリポジトリに対して開発者が直接コミットを行う事は出来ず、コミット可能なのはコミッターのみとする。
コミッターの流れ
最新化(メインSubversionからの変更履歴の取り込み)
-
git svn rebase
を用いて、メインSubversionの変更を取り込みます。 -
git push
で共用リポジトリにメインSubversionの変更をpushする。
ソースの反映(Pull Requestの取り込み)
githubライクに開発者からPullRequestを受け取る事で、メインSubversionへのコミットを行います。
-
git checkout master
でブランチ対象のリポジトリに移動します。 -
git svn rebase
でまずメインSubversionと同期します。 -
git push
によってメインSubversionと共用リポジトリの内容を同期させます。 -
git fetch
で共用リポジトリにpushされたブランチ内容を取得します。 -
git merge --no-ff --no-commit BRANCH_NAME
で変更内容をmaste
に取り込みます。 - 取りこんだ内容が問題ないか動作確認を行います。
- 問題ないようであれば、
git commit
でmaster
にコミットを行います。この際にメインSubversionにコミットするコミットコメントを記述します。 -
git svn dcommit -n
で問題なくメインSubversionへコミットできるか確認を行います。 -
git svn dcommit --interactive
でコミットされるログなどを確認します。 - 問題ないようであれば
git svn dcommit
で変更内容をメインSubversionへ送信します。 - 最後に
git push
で共用リポジトリにコミットした内容を反映させます。
ブランチマージ時のコンフリクト
上記5において、当然コンフリクトが発生する可能性があります。その場合はそのPullRequestの差し戻しを行います。この辺りは通常のgithubのPullRequestと同じ運用ですね。
開発者の流れ
開発者は共有gitのみを参照しながら作業します。
新規ブランチ作成からコミットまでの流れ
-
git clone git-share local-git
でローカルに共有gitをcloneします。 -
git checkout master
でマスターブランチへ切り替えます -
git checkout -b issue/xxx
で障害対応管理単位でブランチを切ります。 - 修正してコミットを繰り返します。
- 修正が完了したタイミングで、
git push origin issue/xxx:issue/xxx
でローカル変更を共用リポジトリにpushします。 -
git request-pull
で修正した内容を取り込んでもらうようにコミッターにメールを行います(当然口頭でも一言言いますが)
共有gitの内容をローカルへ
当然定期的にメインSubversionの内容をローカルへ反映させる必要があります。任意のタイミング以外でも、上記5のgit push
を行うタイミングの前などで以下の手順で最新化します。
-
git checkout master
で共有gitと同期させているmasterへ移行します。 -
git pull --rebase
で最新の変更を取り込みます。
# ローカルのmasterは共用リポジトリのmasterであり、メインSubversionのtrunkとなるため、pull
は--rebase
を強制とします。
問題点
共有gitとメインSubversionの差分をコミッターしか反映出来ない
この点に関してはgitの習熟度に応じて各メンバーにgit-svnの利用を覚えてもらう事で、メインSubversionから共有gitへのルートを広げました。
最後にちょっとだけアクセントを
基本的にはこの構成で問題なかったのですが、共用リポジトリを見る方法を準備していませんでした。
そこで、今回はアトラシアン社のStashを導入しています。
今なら GitBucket という選択肢があったのですが当時はちょうどリリースする前で断念しました。
ただ、Stashのスターターライセンスは有料なだけあって、PullRequestや権限回りがしっかりしていたのでみんながGitのPush/Pull、PullRequestの概念になれるのにとても役に立ったと思います。
というわけですので、SVNからgitに移行しようとしていて躊躇している方は一度試してみてはいかがでしょうか。