ブランチモデル
Motivation
単純にこれらのどれかに従えばそれでうまくいく場合もある (個人の場合はほとんど問題にならないし、なんなら master だけでも問題ない) が、チームで採用するとなると色々考慮しなくてはならない点が出てくる。
業務フローにあわせる チーム内の裁量で決められる部分とは別に、もっと大きな組織的枠組みのなかであらかじめ決められている部分がある可能性がる。例えば、開発のライフサイクルを進めていく上で、必ず他チーム (例えば品証とか) にチェックをもらう必要があるとか、バージョニングの方針とか、など。その場合、それに適合するようなブランチモデルを採用する必要がある
ロールバック ネイティブアプリ等はまた別だが、Web アプリケーションの場合、迅速にロールバックできることが重要になる
そもそも、逆にあまりにもチームに裁量がありすぎると、「こっちの方が好みだから」みたいなふわっとした理由で、適当なブランチモデルが採用されてしまいがち (という現場をみた)。
ブランチモデルはどれがもっとも優れているということはなくて、自分の組織や開発対象の性質に合わせて、適切なものを選ぶべきだ。適切ではないブランチモデルは開発のライフサイクルを滞らせたり、混乱を産んだりする恐れがる。一方、適切なブランチモデルを選択できていれば、開発者の苦痛を和らげ、開発を加速させてくれるはずだ。
あとでよむ
One Flow は聞いたことがなかった
既存のブランチモデル
Git Flow
Vincent Driessen 氏により紹介されたモデル。紹介のブログポストは 2010 年。
table:git flow
ブランチ lifetime from to 命名 役割
master infinite - - - production ready な状態を常に反映している.
develop infinite - - - 開発上の最新の変更を反映している. integration branch とも呼ばれる.
feature (topic) limited develop develop 任意 新機能開発のためのブランチ. どのリリースに含まれるか?は切る段階では不明. merge のときは --no-ff フラグをつけるとよい
release limited develop develop/master release-* リリース準備のためのブランチ. マイナーなバグフィックスや、メタデータの修正 (バージョン番号の修正等) を行う. develop に次回リリースに含める feature が全てマージされた時点で切る.
hotfix limited master develop/master hotfix-* 重大な/緊急のバグ修正のためのブランチ. プロダクションに重大なバグがあり、すぐに直す場合に master から直接切る.
GitHub Flow
2011 年、Git エバンジェリストの Scott Chacon 氏によって紹介されたモデル。GitHub の従業員が 35 人くらいだった時に GitHub 内で使われていたようだ。
Git Flow の問題点は以下。
開発者や開発チームの要求に対して過剰に複雑
helper script があるが、CUI でしか利用できず、Git に慣れていない GUI 利用者にはマニュアルを強要してしまう問題 GitHub Flow の利点は以下。
シンプルで、簡単に理解できる
複雑にしてしまうことや、間違ったことによる手戻りがない
helper script のようなものが必要ない
GitHub Flow の特徴は以下。
"リリース" という概念をなくし、常に master をデプロイ可能として、日々なんどもデプロイする
問題があっても、すぐにデプロイしなおせばよい
デプロイのサイクルが短ければ、たくさんのバグを一度に混入してしまう恐れが少ない
table:github flow
ブランチ lifetime from to 命名 役割
master infinite - - - 常にデプロイ可能. 新たにマージされたら即座にデプロイしなければならない
topic limit master master 任意 新しい何かを行う場合に切る. フィードバックや助けが欲しければ PR を投げる
GitLab Flow
2014 年に GitLab のブログポストで紹介された。開発対象のソフトウェアの性質に合わせて、三種類のブランチ運用方法が紹介されている。
production ブランチ
GitHub Flow の問題点は以下。
master を常にデプロイするのは、SaaS アプリケーションなら可能だが、不可能な場合もある
iOS/Android アプリ等、審査に期間を要する場合
デプロイの窓口を担うチームが別にあり、そのチームの稼働時間外に master にマージすることがある場合
下記は正確にドキュメントを反映していないが (topic ブランチについては明言されていない)、だいたいこのような感じだろうと思う。
table:gitlab flow production
ブランチ lifetime from to 命名 役割
master infinite - - -
production inifinite master - - 実際にデプロイされたコードを反映している. merge した時間でデプロイされた時期が大体 わかるし、自動デプロイしていればさらにわかりやすい.
topic limit master master 任意 新機能開発用のブランチ
環境ブランチ
例えば、staging/pre-production/production のような環境に別れている場合...
master にマージされたら、staging にデプロイ
master -> pre-production にマージされたら、pre-production にデプロイ
pre-production -> production にマージされたら、production にデプロイ
のように、環境毎にブランチを分けておく。
これの良いところは、master で反映したコードがそのまま他の環境にも適用されることが保証されるところ。hotfix があった場合は、まず master から切って、そのあと順次各環境に適用していく。
table:gitlab flow production
ブランチ lifetime from to 命名 役割
master infinite - - -
環境用 inifinite master/ 他の環境用ブランチ - 環境名 (production, pre-production) 環境へデプロイされたコードを反映しているブランチ.
topic limit master master 任意 新機能開発用のブランチ
Release ブランチ
マイナーリリース毎に専用のブランチを切る方式。環境ブランチとは共存しない。
重大なバグ修正があった場合は、まず master にマージしてから、release ブランチに cherry-pick する。これは、upstream first と呼ばれ、Google や RedHat でも活用されている。release ブランチにバグ修正が取り込まれたら、パッチバージョンをあげる。
table:gitlab flow release
ブランチ lifetime from to 命名 役割
master infinite - - -
release inifinite master - バージョン名 マイナーリリース毎に切る. 切るのはなるべく遅くする (あとからバグ修正を追加することを避けるため).
topic limit master master 任意 新機能開発用のブランチ
応用例
GitHub Flow & Releasing Strategy
GitHub Flow でうまくリリースを進めていくにはどうするか?みたいな話。基本的には Release ブランチのようなものは切らず、master にタグをうっていく。hotfix があった場合には hotfix ブランチにタグをうつこともある。
GitHub flow がベースなので、master, topic, hotfix くらいしかブランチが登場せずシンプル。
GitHub の独自機能
GitHub Releases
(WIP) そのうち特徴をまとめておきたい
自動化プラクティス
ブランチモデル内で、自動化可能な作業には以下のようなものがある。
特定の環境へのデプロイ
バージョンの bump
メタデータの更新
タグの追加
GitHub Release の生成
成果物の任意の場所/GitHub Release へのアップロード
CI ツールによる自動デプロイ
CI ツールは世の中にたくさんあり、何にトリガーして何を行えるか?が重要。例えば、TravisCI だと、以下のような条件でデプロイをトリガーすることはできる。 特定のブランチ (完全一致, 正規表現) に対して push されたとき
タグつきで push されたとき
リリース時の作業自動化
release-it
以下を行ってくれる。
package.json 等のメタデータないのバージョンの bump
git commit, tag, push
GitHub の Release の作成と成果物のアップロード
CHANGELOG の生成
npm へのアップロード
conventional-changelog
以下を行ってくれる。
CHANGELOG.md の自動生成
参考
メモ
デプロイ自動化の方法はいくつかあると思う。前提としては、master と topic があり、topic から master へマージする前に必ず PR を作ること。
タグを活用しない場合、master マージ後にすぐにデプロイしてしまって良いと思うけど、tag や GitHub Release を活用したい場合、それらはどのタイミングで作るのが良いのだろうか。
PR を master にマージした段階でデプロイする
master マージ時にはデプロイせず、tag を master に直pushし、そのタイミングでデプロイする
master マージ時にはデプロイせず、release ブランチに push 時点でデプロイする
基本的に、topic 1つマージにつきバージョンを bump はしないはず。ので、master マージ時にバージョンを bump するのは機会がおおすぎる。だから、PR マージ時点でバージョンを bump したりデプロイしたりするのはどうかと思う (純粋な GitHub Flow に従うのであればそれが正しいのかもしれないけど)。
topic をどの程度の粒度で切るのかにもよるのかもしれないけど、レビューのしやすさを考えても topic あたりの粒度はなるだけ細かくしたい。ので、master に対してある程度 topic がマージされた段階で、release 用の何かアクションをして、其の際に各種環境にデプロイ、が良さそう。
この時、GitLab Flow の 環境ブランチ か Release ブランチ かのいずれかに従うのが良さそうに思える。となると、バージョンの bump はこれらブランチへのマージ前に行うのが自然なように思う。
環境ブランチ の場合、bump はまず master で行ってから各種 環境ブランチ にマージしていく。Release ブランチ の場合は、Release ブランチ を切ってから bump しても良いかもしれないけど、結局 master にない変更を Release ブランチ に含めてしまうのは upstream first になっていないきがするので、やはりまず master 上で bump してから Release ブランチ を切るのが良いように思う。
ここまでをまとめると、
master から topic をきる
topic を master にマージする (この時点ではデプロイは行われない. staging へのデプロイなら行っても良いかも?業務フローによる)
master 上で bump するための動作を行う
環境ブランチへマージ or release ブランチを切りデプロイ
「bump するための動作」がどこまで自動化できるか?になりそう。
---
ブランチ運用を考える上で、考えること
ロールバック はどうするか
会社で 統制された運用フロー との適合度
Release はどうするか
ソフトウェアの性質はどうか
本番デプロイが即座に影響を及ぼすか? (パッケージなどの場合は即座に影響はないが、web サービスのような場合は影響があるし、デプロイフローは複雑で慎重なものになる)
どこを自動化して、どこをしないか
つまり、自動化できそうな部分を妥協するか、しないか
人がやった方が良誘うな場合、そのメリットを考える
ブランチ運用で、達成したいこと
Continuous Integration テストが通ることを継続的に確認できる
デプロイ/ロールバック自動化 デプロイのために手動で何かする必要がなく、スムーズなデプロイとその切り戻しができる
ブロッキングされない開発ライフサイクル ブランチを適切に運用することで、開発チームの開発
タグ の意義
開発の歴史の中の重要なポイントに印をつけることができる
その重要なポイントに、注釈をつけることができる (注釈付きのタグ)
Release/Pre-release
ブランチ運用のパターン
環境ブランチ
master から、デプロイ対象の環境にデプロイする用のブランチへと、順次マージしていき、順次デプロイしていく。
コミットがダウンストリームに流れていくだけのワークフロー
テスト済みのものはのちの全ての環境でテスト済みであることを保証できる
リリースブランチ
マイナーバージョンごとにリリースブランチを切る
アップストリームファースト