長らくGitFlowを使っていますが、GitHub Flowを使っている案件に携わってみて、疑問を感じたので、どっちが(もしくは別の方法)が良いかを改めて考えてみました。
GitFlowとGitHub Flowの違い
端的に言うと、develop
が有る(GitFlow)か、develop
が無い(GitHub Flow)かの違い。
リリース後は、master
とdevelop
が一致するので、2つは不要と、2つあると乖離する可能性があるというのが、GitFlowの欠点らしい。
GitFlowではブランチと環境が一致させられるので、STGがdevelop
で、本番がmaster
になる。
GitHub Flowでは、STGがmaster
で、本番はmaster
の特定の位置(タグ等で管理)になる。
featureブランチ
ブランチ名(例): feature/123_xxxxx
GitFlowはdevelop
、GitHub Flowはmaster
から切って、元のに向けてPRを作るので、対象が変わるだけで手順は変わらない。
hotfixブランチ
ブランチ名(例): hotfix/xxxxx
GitFlowはmaster
から切って、develop
とmaster
に向けてPRを作る。
欠点:develop
マージを忘れるとmaster
との乖離が発生する。
解決策: STGで動作確認、本番リリースという流れを守れば、乖離する事はない。
GitHub Flowでは、featureブランチと同じ流れになる。
欠点:master
に動作確認できていないものが含まれているとリリースできない。
対応: 動作確認を急がせる or リバートする。 → 急いでいる時に手間が増えるのは痛い。
ECSやK8s(Kubernetes)、Capistrano等を使っている場合は、切り戻すのが早いのですが、
切り戻せないケースもあるので、hotfixが使えないのは痛い。
releaseブランチ
ブランチ名(例): release/123_xxxxx
master
マージ後のdevelop
から切って、develop
とmaster
にマージする。
ブランチ名(例): release/123_xxxxx <- release/feature/123_yyyyy
私は、厳密にreleaseブランチの流れを使った事はないですが、
PRが大き過ぎる場合に、develop
の最新から切って、そこからfeatureブランチ切って、releaseブランチに向けてPRを何回かに分けて出して、最終的にreleaseブランチをdevelop
に向けたPRを出してマージしています。develop
向けのPRは動くものにした方が良い。
この流れはGitHub Flowでも使えます。
ちなみに、PRが大き過ぎても分割せず、featureブランチで行く事もあります。
この場合は、コミット単位が重要で、多過ぎない意味のある単位でコミットを積んでいれば、コミット毎にレビューする事が可能になります。
続けてレビューするか、別々にレビューするかの違いですが、チームによっては、大きいのを嫌がるので、使い分けています。
それぞれの課題
GitHub Flowの課題
GitHub Flowではmaster
はリリースできる状態を保つ必要がある。ゆえにマージ&STGデプロイされたら、直ぐに動作確認しなければならない。
STGでは短時間で完了する必要がある為、詳細な動作確認(テスト)はマージ前に、ローカルやブランチ専用の環境(検証環境)で行う必要がある。→ ローカルでテストするのは微妙
検証環境が、本番やSTGと同様、連携先含め常に動く状態を保つ必要がある。→ これが結構難しい
STGで動作確認(テスト)しようとすると、リリースブロック(バグがあってもリリースできない状態)が必要になる。
GitFlowの課題
GitFlowではdevelop
がリリースできる状態にならないと、master
マージ(=リリース)できない。
GitHub Flowと異なり、直ぐに動作確認(テスト)しなければならない訳ではないので、後回しが続くとリリースできない状態が続く。
ゆえに、予めリリース日を決めて(定期リリース)、そこに向けてテストする事が多い。
定期リリース以外にリリースする場合、動作確認(テスト)が完了しているかの確認と、マージブロックが必要になる。
リリースタイミング
GitHub Flowではhotfixが使えないので随時リリースしか選択肢がないが、
GitFlowでは定期リリース以外の選択肢も取れる。
GitHub Flowじゃないと、リリース頻度を上げられない?
No。GitFlowではdevelop
、GitHub Flowではmaster
が、リリース可能な状態になっていればいつでもリリースできる。但し、GitHub Flowではマージ前に検証環境でテストするのに対して、GitFlowではdevelop
マージ後にテストするので(検証環境で事前にテストする事も可能)、リリース可能な状態の時間が短くなる。
GitHub Flowの方がリリース可能な状態が長いので、リリース頻度を上げやすいが、
GitFlowでも検証環境を使えばリリース可能な状態の時間は変わらない。
随時リリースは非効率!?
PRをマージしたら必ずリリースしなければならない訳ではない。
バグ対応や機能追加は早くユーザーに届けたいけど、リファクタやテスト追加、プログレッシブデリバリー(早期マージ。Feature Flagや環境変数(本番サーバーかどうか)でリリース制御)等の場合は、急いでリリースする必要がない。
未リリースのPRが溜まって行くが、皆が直ぐに動作確認したとしても、開発者の人数に比例して、リリースできない状態が長くなる。
直ぐに動作確認してくれない人も出てくるので、確認の為のコミュニケーションコストが増える。
環境にもよりますが、10人前後なら問題なさそうだが、20人ぐらいになると開発ストレスが増える。逆に数人だとリリースされない期間が長くなる。
リリース作業は自動化されている場合が多いとは言え、完了までに時間は掛かるし、経過観察も必要になるので、リリース回数が多いと効率が悪い。
ゆえに、リリース作業は避けたくなるので、気を利かせた特定の人にリリース作業が集中する。
定期リリースだと価値提供が遅れる
決まった日にリリースする方が効率的ではあるが、ユーザーへの価値提供は遅くなる。
とは言え、バグ対応を除けば、毎日届けたいものがあるかと言うと疑問な場合が多く、開発ストレス軽減も考慮すると週1〜2回で十分だと思う。
定期リリース以外に、特定の機能だけの臨時リリースを入れられれば、最短で価値提供でき、他のチームやメンバーに負担が掛からないのでベストだと思う。
夕方以降や休前日のリリースは避ける
リリース起因で、障害(インシデント)が発生した場合に、定時での対応が難しくなるので、定期リリースでは日時を気にする事が多い。
随時リリースだと気にしない事が多いと思われるが、気にした方が良い。自分たちの首を絞める。
※DB処理に時間や負荷が掛かったり、メンテナンスが必要なリリースは除く。
【解】GitFlow+定期リリース&hotfixを使用した臨時リリースの提案
GitHub Flowは少人数か、常にルールを守れる(開発ストレスを減らせる)場合は良いと思うが、hotfixが使えないのは痛過ぎる。
定期リリースは開発ストレスを減らせるが、ユーザーへの価値提供が遅れる。
価値提供は随時リリースでなくても、臨時リリースでも早くできる。
但し、master
やdevelop
との乖離が長いと、コンフリクトや思わぬバグに見舞われる事もあるので、長期開発ではプログレッシブデリバリーを使った方が良い。
固定概念を捨てる
hotfixは緊急リリース用と思いがちだが、機能開発に使用しても問題ない。
ブランチ名(例): hotfix/123_xxxxx or <- hotfix/feature/123_yyyyy
臨時リリースしたい(定期リリース前にリリースしたい機能がある)場合に、
hotfixの流れで、master
からブランチを切って、develop
にPR・マージ&STGで動作確認した後、master
にPR・マージしてリリースする。
もし定期リリース直前になってしまったら、develop
だけにして、定期リリースの流れに乗せる。
もし定期リリース後になってしまったら、master
をマージして、開発を継続できる。
これで開発ストレスも増やさずに、価値提供のスピードも上げられる!!!