ちょっと話題の記事

GitのRebaseによるBranchの運用

2015.01.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。 東京では雪が降って騒ぎになっていますが、札幌では雨が降って騒ぎなっています。 これっていわゆる「北から目線」ですが、目線の違いってのは結構大切なことです。

はじめにお断りしておきますが、今回紹介する手法はひとつの運用方法です。 自分はこんなやり方が好きだ/嫌いだといったことを言われても、「そうっすかw」としか言えません。 特にGitを使うと様々なやり方があるでしょう。 それらを否定するつもりも、今回紹介する方法が完璧な方法だとも考えていません。 あくまでGit(バージョン管理)運用手法のひとつとしてご紹介いたします。 マサカリを投げるのは歓迎しますが、好みの押しつけはご遠慮ください(笑)

メインBranchへのMerge

安全なMergeを行う開発フローでも解説しましたが、Gitでは各開発者がそれぞれ作成したBranchに変更をCommitし、最後にメインBranchへMergeする開発フローが推奨されます。 しかし、適切な開発フローを整備していっても、Merge時のConflict(競合)の可能性はゼロにはなりません。 つまり、Conflictしてしまった場合は手動でMergeしなければなりません。

でも、手動Mergeはなるべく楽に行いたいですね。

逆Merge

一般的なMergeでは開発BranchをメインBranchにMergeします。

この時、Conflictが発生するとメインBranchでの修正作業が発生します。 しかし、タイミングが悪かったりMergeに時間がかかってしまうと様々な問題が発生します。 例えば、やっとMergeが終わったのにPushしようとしたら、メインBranchが更新されてしまっていた・・など。 また、メインBranch上で作業を行いConflictを解消することは「怖い」と感じる人は多いと思います。

branch

この問題を解決するひとつの方法が逆Mergeです。 逆Mergeは、先にメインBranchを開発BranchにMergeします。 言い換えると、メインBranchの変更を開発Branchに取り込むということです。 逆Mergeを行った後、メインBranchへMergeします。

r-merge

開発Branchで落ち着いてMergeできる

逆Mergeは、開発Branchに対して変更を加える操作です。 メインBranchへの影響はありませんので、メインBranchへのMergeよりも「怖さ」を少なく感じます。 Conflictが発生した場合でも、開発Branchで落ち着いて作業できます。

メインBranchのMergeでConflictが発生しない

逆Mergeによって、メインBranchの変更内容は開発Branchに適用されています。 したがって、メインBranchへのMergeを行う時に、Conflictは発生しません。 正確にはConflictが発生するケースであっても、逆Mergeの時に解消しているワケです。

メインBranchの変更で開発Branchで影響がないか確認出来る

開発Branchでの変更がメインBranchにMergeされると不具合となるケースがあります。 例えば、共通で使うAという機能に問題があり、メインBranchで修正されているとします。 開発BranchではBranchを作成した時点、すなわちAという機能に不具合がある状態だったため、不具合を条件として機能が実装されているかもしれないのです。 この場合、Mergeを行うと予期せぬ不具合に発展します。

逆Mergeを行い、動作確認を行ってからメインBranchにMergeすると、このような問題を早期に発見することが出来ます。 ユニットテストを行っているのであれば、逆Mergeしユニットテストを実行した後にMergeする運用も良いでしょう。

マメに逆Mergeする

開発Branchで作業を行っている時、一番厄介なのは開発Branchが中々クローズできないケースです。 基本的には避けていきたいところですが、どうしてもクローズできない場合もあるかと思います。 そのような場合は、定期的にー1日に1回などーメインBranchを逆Mergeすると効果的です。 メインBranchとの距離を定期的に詰めるため、Conflictが発生しても影響範囲が少なくなります。 最終的にメインBranchにMergeする場合にも安全となるでしょう。

r-merge2

Rebaseでの運用

逆Mergeの運用はどんなバージョン管理システムを使った場合でも適用できます。 が、Gitにおいては逆Mergeの代わりにRebaseを使うと、よりクールに運用できるのでお勧めです。

Branchの根元を変えるRebase

Rebaseは、結果として逆Mergeと同じ状態となります。 異なるのは変更の適用方法です。

Rebaseでは、はじめにBranchでのコミット内容をGitのキャッシュに保存しておいた上で、Branchの開始場所をRebase場所に変更します。 その後に、それまでBranchで変更してきた内容を、新しいBranchに適用していきます。

rebase

RebaseされるとBranchの初期状態が変わります。 とはいっても、Rebaseで変更されたファイルに対して開発Branchで変更を加えていなければRebaseはそのまま終了します。 これはConflictしていない状態です。

もし、Rebaseで変更されたファイルに対して開発Branchで変更を加えていたならば、Conflictが発生する可能性があります。 Conflictしてしまったならば、Rebaseは一時中断となります。 その時点でConflictしたファイルを手動で解決しなければなりません。

Conflictを解決したならば、Rebaseを再開します。 またConflictしたならば解決といった形で最後までBranchの変更が再適用されるとRebaseは終了します。

最終状況にメインBranchの変更を適用するか、Branchの初期状態を変更してから開発Branchの変更を再適用するか

ここには大きな視点の違いがあります。

他の開発者が変更した内容は把握しきれるものではありません。 自分の開発Branchに適用するときに影響などを考えると判断できない場合もあるでしょう。 逆に元が変わって自分がこれまで変更してきた内容を再適用する方が、変更する意図を自分で知っている分楽なのです。

ここがRebaseのクールなところです。

Rebase運用

Rebaseで運用する場合も、逆Mergeの運用と同様のメリットがあります。 先にメインBranchの内容が適用されるため検証を行うこともできますし、長期間Branchを生やしていた場合でもメインBranchへの変更に追従することができます。 もちろん、開発BranchをメインBracnhに適用する場合にConflictは発生しません。

まとめ

Mergeが不安な場合はこまめにRebaseを行う運用とすると良いでしょう。

Rebaseにより開発Branchで落ちついてMergeができます。 Conflictした場合も自分の変更した内容を適用していくので逆Mergeよりも楽でしょう。

BranchとRebaseを使ってクールなGitライフを送りましょう!

なお、Rebaseとか逆Mergeとかしなくても、メインBranchにMergeすればいいじゃん!って方はそれで良いでしょう。 ですが、開発チームがGitに不慣れな場合は、Rebaseを使うことでGit導入の敷居が低くなりますので、導入を検討してみてください。