Gitのブランチ運用でちょっと試行錯誤した話

先日の健康診断で即メタボ認定を受けて危機感を覚え、酒量と食事量を減らしつつありますが、まだ効果が表れていない下條です。このブログで定期的に体重を公開すればさらに意識が変わるかなと思いましたが、皆さんそんなものは見たくないと思いますので書きません。

さて、私は以前の会社ではソースコードのバージョン管理にSubversion的なものを使っており、弊社に入社してから本格的にGitを使い出しました。そこで最初に参加した受託Webサービス開発のプロジェクトにおいて、Gitを使ったブランチ運用についてちょっと試行錯誤した経緯をご紹介します。

GitHub Flowとの出会い

Gitのブランチ運用の方法として有名なものとして、GitHub FlowA successful Git branching model (O-Show 氏による日本語訳) (以後git-flowと記述)の2つがあります。私が弊社に入社してGitを使い始めたときは、受託Webサービス新規開発のまっただ中で、ほぼGitHub Flowに準じたフローとなっていました。
一応GitHub Flowの概要を書いておきます。

  • masterブランチのものは何であれデプロイ可能である
  • 新しい何かに取り組む際は、説明的な名前のブランチをmasterから作成する(例: new-oauth2-scopes)
  • 作成したブランチにローカルでコミットし、サーバー上の同じ名前のブランチにも定期的に作業内容をpushする
  • フィードバックや助言が欲しい時、ブランチをマージしてもよいと思ったときは、 プルリクエスト を作成する
  • 他の誰かがレビューをして機能にOKを出してくれたら、あなたはコードをmasterへマージすることができる
  • マージをしてmasterへpushしたら、直ちにデプロイをする

https://gist.github.com/Gab-km/3705015 から引用。)

このフローはシンプルで分かりやすいです。そして、Pull Requestを利用してレビューをプロセスの中に組み込んだ開発フローってなかなかいいなと思っていました。(実際にはソースレビューがきちんとされないプロジェクトをこれまでたくさん見てきたので。)
このフローは、開発段階では基本的にはうまくいくと思いますし、実際にうまくいっていました。

GitHub Flowとの別れ

リリース後に運用・保守開発フェーズに入り、機能追加・バグフィックスをするにあたって、ブランチをどう取り扱うかというところでGitHub Flowではうまくいかなくなりました。
まず、そのプロジェクトでは、リリースについて以下の前提条件がありました。このルールは特に受託開発においては例外的なものではないと思います。

  • ステージング環境と本番環境があり、機能追加・修正はお客様のOKが出たものからステージング環境で動作確認する。
  • どの機能追加・修正を本番リリースするかは最終的にお客様が決める。

この場合、GitHub Flowのように随時masterブランチにPull Requestしてマージしていくと、masterブランチは本番環境と乖離していってしまいます。即本番リリースができるブランチがないというのはいろいろと困ります。緊急のバグフィックスをしたいというときなどに困ります。また、後からこれこれの修正はリリースしないなどと言われた場合にmasterブランチからコミットをrevertしたりするのは嫌なものです。特にrevertでコンフリクトしたりすると非常に嫌です。
結局、上述したURLの中にも記載されている通り、GitHub Flowではきちんとしたリリースというものがないことを前提としています。やはり、リリースが存在する受託開発での運用・保守開発フェーズや、自社の場合でもリリースには誰かの承認がいるといった場合にはGitHub Flowはなかなかマッチしません。
というわけで、今回の事情に合わせた、新たなGitのブランチ運用を検討することにしました。

新たな運用を模索してgit-flowを調査

GitHub Flowがダメだったらgit-flowかなということでgit-flowを調べてみました。

git-flowでは5種類のブランチを使用します。

  1. developブランチ
    開発を行うためのブランチ。開発者は、主にこのブランチ上で作業を行う。次に紹介するfeatureブランチなど、他のブランチで行った作業は、ここにマージされる
  2. featureブランチ
    主要な機能を実装するためのブランチ。機能の実装やバグフィックスなど、タスクごとにfeatureブランチを作成し、作業を行う
  3. releaseブランチ
    リリースの準備を行うためのブランチ。プロダクトをリリースする前に、このブランチを作成し、微調整を行う。releaseブランチを作成することで、リリース準備と次のバージョンに向けた開発のコードを分けることができる
  4. masterブランチ
    リリースしたソースコードを管理するためのブランチ。リリース作業を行うと、releaseブランチはmasterブランチへマージされて、リリースタグが打たれる。開発者は、このブランチへのコミットは行わない
  5. hotfixブランチ
    リリースされたソフトウェアに緊急の修正を行うためのブランチ。このブランチでの修正内容は、すぐにリリースされるので、hotfixブランチはリリースを管理するmasterブランチへマージされる

http://www.atmarkit.co.jp/ait/articles/1311/18/news017.html から引用。)

GitHub Flowに比べるとかなりややこしい運用となります。今回のプロジェクトの場合、開発者も少ないし、機能追加・修正がそこまでたくさんあったわけではなかったので、git-flowほどがんばってやる必要はないのではないかと思いました。git-flowほどがんばりたくはないけれどもGitHub Flowでは要件を満たさないといった場合にどういった運用にするかということで検討し、何回かの試行錯誤の末、以下の運用にすることにしました。

採用したブランチ運用

masterブランチ、stagingブランチという2つのメインブランチを保持。

  • masterブランチ: サービスをリリースするためのブランチ。常に本番環境で動いているブランチとなる。リリースしたらタグを付ける。
  • stagingブランチ: お客様からステージングでの検証許可が出た修正のみが入っているステージング検証用ブランチ。本番リリースの許可が出たらmasterへマージする。

各開発者は機能追加・バグフィックスにおいては全てtopicブランチを作成して開発する。

  • topicブランチ:機能の追加、バグフィックスなど全ての作業はmasterからブランチを切って行う。stagingにプルリクエスト、レビューする。レビューで全員のOKが出た後、お客様からステージング環境での検証許可が出た時点でstagingにマージする。
    topicブランチはmasterマージ後破棄する。

→おおざっぱに言うと、git-flowのhotfixブランチおよびdevelopブランチがない簡易バージョンのような感じです。

hotfixブランチがない理由

masterから分岐し、masterにマージする、hotfixブランチは作成しません。どんな修正でも、ステージング環境でお客様が確認した後に本番リリースというルールがあるため、必ずまずstagingブランチにマージすることになります。

developブランチがない理由

ここはちょっと微妙なのですが、修正の数、開発者の数が少なかったため、リリースの前にtopicブランチをstagingブランチにマージすればよいと考えました。そのため、git-flowでdevelopブランチにあたるブランチは作成しませんでした。

ただし、この運用の問題点として、リリース許可が出た段階でstagingブランチに一気に多くのtopicブランチをマージしなければいけない状況が発生する場合があります。一概には言えませんが、お客様には修正自体にかかるコストはそれなりに理解していただけるものですが、リリース準備の際に修正をマージするコスト、リスクはなかなか理解していただけないものです。リリース許可が出たtopicブランチを一気にstagingブランチにマージをすると、修正同士の影響がどれだけ発生するか分からず、リスクが見えないのはよろしくありません。
それを考えると、レビューが済んだtopicブランチは、いったんなんらかのブランチにマージしておき、修正同士の影響を予め把握しておく方がよいとも思います。git本家が推奨するワークフローの中でも「使い捨ての統合ブランチ」を作成することが推奨されています。そして、リリースが近くなったらtopicブランチをstagingブランチにマージしてリリースに向けた調整をすると。
ただし、今回のプロジェクトは小さくてメンバーも少なく、あまり大量の修正が入ることもなかったため、各修正同士の影響が見えることがほとんどだったために、使い捨ての統合ブランチは作りませんでした。
結果、git-flowよりもだいぶ簡易な運用となり、現状はまあうまくいっています。

まとめ

当然ではありますが、必ずしもGitHub Flowやgit-flowが現実とマッチするとは限りません。GitHub Flowやgit-flowはおそらくベストプラクティスのようなものですが、Gitのブランチ運用は、ある意味汚い現実の開発・リリースプロセスと密接に絡んでいるので、開発・リリースプロセスを含めながら、その都度良い運用を考えていくのがよいと思います。デザインパターン的なものがあればうれしい気はしていますが。

このエントリーをはてなブックマークに追加