ブランチの名前はチームごとに違うのに、会話では Git Flow と GitHub Flow がよく出てきます。作業の切り方だけ見ると、どちらも feature ブランチを切り、レビューしてから戻します。
分かれるのは、本番に届くまでに置く長期ブランチの本数です。Git Flow は main と develop の2本を置き、出す直前に release で固めます。GitHub Flow は main だけを置き、入った変更をそのまま出します。
見るのは3点です。どの線が本番か。feature はどこへ戻るか。出したあとの不具合を、どの線で直すか。ここが分かると、出す頻度に対してどちらが合うかまで判断できます。
用語
タグ
タグは、あるコミットを名前で指す印です。ブランチは先へ進みますが、タグは打った位置から動きません。
Git Flow では、main に戻したコミットへ v1.0 のように付けます。本番に出す中身は、このタグが指すコミットです。
デプロイ
デプロイは、そのコミットが本番環境で動くことです。ブランチを戻したあと、パイプラインがそのコミットを本番へ載せます。
リリース
リリースは、ユーザーがその機能を使えるようにすることです。Git Flow の release ブランチは、今出す版を固める線の名前です。ここでいうリリースは、その線のことではありません。
feature flag があるとき、デプロイは済んでいても、その機能のリリースはまだ、という状態があります。フラグをオンにしたときが、その機能のリリースです。フラグの置き方は 【Feature Flag】デプロイとリリースを分ける にあります。
作業ブランチはどちらも切る
どちらの流れでも、長期のブランチへ直接は積みません。変更は短い作業ブランチで作り、pull request で差分を見てから、元の線へ戻します。
戻す先は、図で feature が合流する本線です。Git Flow ではこの線が develop、GitHub Flow では main になります。戻す先の名前は違います。作業を一度分けてから戻す形は同じです。
gitGraph commit id: "本線" branch feature checkout feature commit id: "作業" checkout main merge feature id: "レビューして戻す"
図: 作業は本線から分かれ、レビューのあと本線に戻る。この本線が develop か main かは、流れごとに違う。
Git Flow
永続で残るブランチは、main と develop の2本です。feature、release、hotfix は、用が済めば消えます。
長期ブランチは main と develop の2本
main にあるものは、すでに本番へ出ている版です。main に新しいコミットが載るのは、版を出すときだけです。載ったコミットにはタグを打ち、そのコミットが本番の中身になります。
develop は、次に出す版の統合先です。機能はいったんここに集まります。develop 自体は本番へ出しません。
feature は develop に戻す
機能の作業は develop から切り、終わったら develop に戻します。この時点では main に届きません。本番の版はそのままです。
gitGraph commit id: "起点" branch develop checkout develop commit id: "次の版" branch feature checkout feature commit id: "機能" checkout develop merge feature id: "developへ戻す"
図: feature は develop から分かれ、develop に戻る。main にはまだ届かない。
release で固めてから出す
release を切るのは、今出す版のテストと、次の版へ向けた機能追加を同時に進めるためです。
develop のままテストすると、テスト中にも次の機能が同じ線に入ります。直したそばから中身が変わるので、この版として出すものが固まりません。release は、切った時点の develop を写した一時的な線です。ここでは不具合と版番号だけを直し、機能は足しません。そのあいだ develop には、次の版の機能を入れられます。
【release を切ったあと】develop
「機能Bは次の版なので、こちらに積む」
【同じ時間】release
「今出す版の不具合だけ直す。機能は足さない」
テストが終わったら、release を main に戻します。戻したコミットにタグを打ちます。本番へ出す中身は、このタグが指すコミットです。パイプラインがタグの push で動くか、main へのマージで動くかは、CI/CD の設計で決めます。
同じ release は develop にも戻します。release 上で直した不具合を、次の版に残すためです。
gitGraph commit id: "起点" branch develop checkout develop commit id: "機能A" branch release checkout release commit id: "不具合修正" checkout develop commit id: "機能B" checkout main merge release id: "v1.0" tag: "v1.0" checkout develop merge release id: "修正を戻す"
図: 機能Aまでを release に写し、不具合だけを直す。同じ時間に develop では機能Bが進む。整ったら main に戻して v1.0 を打ち、修正は develop にも戻す。
hotfix は両方に戻す
本番で急ぎの不具合が出たら、今の版と次の版の両方に修正を残します。main だけ直すと、次の release を develop から切ったときに、その修正が抜けます。
hotfix は、いま本番に出ているタグのコミットから切ります。develop からは切りません。次の版の機能が混ざるためです。hotfix 上で直して確認したら、main に戻してパッチのタグを打ちます。本番へ出す中身は、そのタグが指すコミットです。デプロイのきっかけは、release のときと同じで、CI/CD の設計次第です。
同じ hotfix は develop にも戻します。
gitGraph commit id: "v1.0" tag: "v1.0" branch develop checkout develop commit id: "次の版の機能" checkout main branch hotfix checkout hotfix commit id: "本番の修正" checkout main merge hotfix id: "v1.0.1" tag: "v1.0.1" checkout develop merge hotfix id: "developへ戻す"
図: hotfix は本番の v1.0 から切る。次の版の機能は入らない。v1.0.1 を main に打ち、同じ修正を develop にも戻す。
向く出し方
出す日が決まっていて、版を固めてから本番へ出すときに向きます。テストのあいだ次の版の開発が続くなら、release がその重なりを受け持ちます。
重ならなくても、定期的に版を固めて出すなら同じ形です。本番の線は main の1本で、出した版はタグで残ります。
GitHub Flow
原則は、main がいつでも本番に出せることです。ブランチの形は、ここから決まっています。
永続で残るブランチは main だけです。develop も、版を固める release も、hotfix 専用の線も置きません。
長期ブランチは main だけ
いつでも出せるなら、本番を壊す未完成は main に置けません。main に戻ったものは、本番で動いてよいものだけです。
次の版を溜める本線は要りません。溜める場所を置くと、main とは別に、まだ出せない変更の線ができます。この形は、main を常にデプロイできる状態に保ち、戻したものを頻繁に出す前提です。版を固めてから出す運用では、固める線が要ります。次の版の開発と重なっていなくても、定期リリースなら同じです。
feature は短く、main に戻す
機能の作業は main から切ります。ブランチは短く切り、レビューが済んだら main に戻します。
大きい機能は、ユーザーに届くところまで小さく完結する単位に分けます。単位ができるたびに main へ戻すので、作業ブランチはそこで終わります。戻した時点でデプロイされ、同時にリリースになります。
feature flag がないときは、見せられる単位だけを戻します。まだ見せられない残りは、次の単位ができるまで作業ブランチに置きます。
gitGraph commit id: "本番" branch feature checkout feature commit id: "機能" checkout main merge feature id: "mainへ戻す"
図: feature は main から分かれ、レビューのあと main に戻る。戻したコミットが、次の本番になる。
feature flag があるときは、コードを main に戻すことと、ユーザーに見せることを分けられます。コードは本番で動きますが、フラグはオフです。既存の動きは壊れていません。見せると決めたとき、ブランチを切り直さず、フラグをオンにします。オンにしたときが、その機能のリリースです。値の読み方は 【Feature Flag】デプロイとリリースを分ける にあります。
【main に戻したあと】本番
「このコミットは動いている。新しい機能のフラグはオフだ」
【見せると決めたとき】
「フラグをオンにする。ブランチは切り直さない」
sequenceDiagram
participant Dev as 開発者
participant Prod as 本番
participant User as ユーザー
Dev->>Prod: ① main に戻してデプロイ
Note over Prod: ② フラグはオフ<br/>ユーザーには見せない
Dev->>Prod: ③ フラグをオン
Prod-->>User: ④ ここでリリース
図: フラグがあるときは、デプロイしたあとも機能はオフのまま。オンにしたときがリリース。
デプロイは main に入ったあと
main に戻ったものは、本番へ出せます。確認を先にしたいときは、マージ前にその作業ブランチを出して確かめます。確かめているあいだに main が進むことも、マージで新しいコミットができることもあります。戻した main は、確認したブランチそのものとは限りません。マージ後の main も CI で確認してから、本番へ出します。
タグの push で出すか、main へのマージで出すかは、CI/CD の設計です。どちらのきっかけでも、main をいつでも出せる状態に保つ点は同じです。
本番の修正も同じ一本
本番の修正も、機能追加と同じ形です。main から切り、main に戻します。戻り先は main だけです。戻した修正は、今の本番にも、このあとに続く変更にも入ります。
gitGraph commit id: "本番" branch feature checkout feature commit id: "機能" checkout main merge feature id: "機能を戻す" branch fix checkout fix commit id: "本番の修正" checkout main merge fix id: "修正を戻す"
図: 機能追加も本番の修正も、main から切って main に戻る。別の戻り先はない。
向く出し方
main を常にデプロイできる状態に保ち、戻したものを頻繁に出すときに向きます。
まだ見せない機能は、見せられる単位に分けて戻すか、フラグをオフにして main に載せます。
並べるとどこが違うか
違いは、永続ブランチの本数と、本番に届くタイミングです。
| Git Flow | GitHub Flow | |
|---|---|---|
| 永続ブランチ | main と develop | main だけ |
| feature | develop から切り、develop に戻す | main から切り、main に戻す |
| 版を固める間 | release でテストし、develop は次の版を進める | 固める線は置かない |
| 本番の修正 | main と develop の両方に戻す | main に戻す。機能追加と同じ |
| まだ見せないもの | 本番の main には載せない。次の版は develop に置く | 見せられる単位に分けて戻す。フラグがあれば未公開のまま main に載せる |
| 本番へ出す中身 | main に戻したコミット。タグで指す | main に戻したコミット |
Git Flow は、今の版と次の版を別の線に置きます。release のあいだも develop は動き、hotfix は両方に戻します。
GitHub Flow は、本番と次の統合先を main の1本にします。戻したものは出せる状態です。まだ見せない機能は、見せられる単位に分けて戻すか、フラグをオフにしてデプロイとリリースを分けます。
どちらの流れでも、デプロイのきっかけは CI/CD の設計です。タグの push か、main へのマージかは、ブランチの形とは別に決めます。
どちらを選ぶか
main を常にデプロイできる状態に保ち、戻したものを頻繁に出すなら、GitHub Flow です。まだ見せない機能は、見せられる単位に分けて戻すか、フラグでデプロイとリリースを分けます。
版を固めてから本番へ出すなら、Git Flow です。テストと次の版の開発が重なるときは、release がその重なりを受け持ちます。重ならなくても、定期的に版を固めて出すなら、固める線は同じように要ります。
sequenceDiagram
actor U as あなた
participant Q as 出し方
U->>Q: ① main を常に出せる状態に保ち、頻繁に出すか
alt はい
Q-->>U: GitHub Flow<br/>main だけ
else いいえ
Q-->>U: Git Flow<br/>版を固めてから出す
end
図: 頻繁に出すなら GitHub Flow。版を固めてから出すなら Git Flow。次の版の開発と重なっていなくても、定期リリースなら Git Flow。
まとめ
永続ブランチは、Git Flow が main と develop の2本、GitHub Flow が main の1本です。
Git Flow では、release で今の版をテストしながら、develop で次の版を進めます。本番へ出すのは、main に戻してタグを打ったコミットです。本番の修正は、今の版と次の版の両方に戻します。
GitHub Flow では、main をいつでも出せる状態に保ち、戻したものを頻繁に出します。機能追加も本番の修正も、見せられる単位で main に戻します。
フラグがあれば、デプロイしたあとに、その機能のリリースを分けられます。マージ後の main は、確認した作業ブランチそのものとは限らないので、CI で確かめてから本番へ出します。