Gitのブランチ戦略にはいくつかあります。
- Gitフロー
- GitHubフロー
- GitLabフロー
チームの戦略を考えるときにどれかを参考にしつつカスタマイズするときにいろいろ不都合が生じてしてきて複雑になってしまうことってありますよね? 社内でブランチの管理の議論をする中で、ブランチの役割を明確にした上で、どのブランチがどのような役割を持っているのかを明確にした方が混乱が少なくなるのではないか? というのを考えていました。
特に、プロジェクトごとに同じ名前でも役割が違うなー、というのとかもあり、ブランチ名=役割ではなく、ブランチの上位概念として役割を考えて、それを実際のブランチとの対応づけを行う必要があるのではないかな、と。
CI/CDと組み合わされることで、releaseブランチ==ステージング環境となってしまい、ステージング環境を使いたいリリース前のブランチと、ホットフィックスの検証のブランチのブランチマージ戦略がごっちゃになったりして困っている、という相談を受けたこともあって、ぼんやりと考えていたことをまとめました。
このエントリーでは各フローの紹介の図は次のブログから引用しました。各フローの流れを同じスタイルで紹介していて見比べやすかったからです。なお、参照したエントリーではtrunk based developmentもありますが、本エントリーでは省略しています。
ブランチの役割
4つの役割を考えてみました。この後説明しますが、このロールは直接ブランチ名と1:1でリンクするものではありません。
役割 | 何をやるところか? | 許可される変更作業 |
---|---|---|
作業 | ソースコードの変更(機能追加) | 直接のコミット、rebase |
集積 | いろいろな作業の結果を貯める | 作業ブランチや、他の集積ブランチのマージ |
スナップショット | とある時点のコードを保存 | なし |
環境 | CDのトリガーとなって成果物を生成・デプロイ | なし |
環境ブランチというのは後述のGitLabフローから持ってきたもので、他のものは適当に考えてみた名前です。もし良い呼び名があれば提案をお待ちしています。
各フローのブランチと役割の対応
Gitフロー
もしかしたら、この分類に違和感を感じるかもしれませんが、オリジナルのGit Flowになるべく忠実に書いています。あ、masterはmainに変えています。
ブランチ | 役割 | 説明 | 分岐元 | マージ先 |
---|---|---|---|---|
main | 環境 | リリース対象のコードを保持 | なし | なし |
リリースタグ | スナップショット | リリースブランチをmainマージしたタイミングで打つ | develop | main |
develop | 集積 | featureで作業した結果をマージ | なし | release/x |
release/x | 作業/環境 | リリースに向けたバグ修正作業を行う | develop | main/develop |
feature/x | 作業 | 機能の実装作業を行う | develop | develop |
hotfix/x | 作業 | バグの修正作業を行う | main | main/develop/release(あれば) |
releaseブランチではバグ修正作業を行なって修正したものはdevelopに書き戻す、リリースが終わればブランチを削除ということがGitフローでは書かれています。つまり作業用ブランチなのですよね。今時はreleaseは直接コミット禁止にしてそこへの変更もPull Requestにするという運用が多い気がします。あとは、releaseブランチはstaging環境に対する環境ブランチになっており、ここにマージするとstaging環境も自動更新されるとかも良く見る気がします。
GitHubフロー
GitHubフローは明確なブランチ名を定義していません。ここではmainとfeature/xにしています。
ブランチ | 役割 | 説明 | 分岐元 | マージ先 |
---|---|---|---|---|
main | 集積 | featureで作業した結果をマージ | なし | なし |
feature/x | 作業 | 機能の実装作業を行う | main | main |
ブランチを切ってコミットし、Pull Requestを作成してそれ上でコメントをしたりレビューします。完了したらGitHubの機能を使ってマージします。
GitHub Actionsを駆使するのも最近ではよく行われていますね。mainではデイリーでビルドを走らせてnightly buildを作成する、というのが行われることもあります。その場合は環境ブランチでもある、ということになります。main上でタグを打ったらリリース、という場合は、このタグがスナップショットですね。
GitHubフローだけだとCD環境へのデプロイとかのルールはこの上には作りづらいため、GitHubフローはプリミティブなビルディングブロックとしてGitフローやGitLabフローをアレンジした戦略を組み合わせて使うことが多いでしょう。
それにしても、GitHubフローのドキュメント、プルリクウェストってカタカナ表記が渋いですね。Pull Requestを発明したGitHub公式が書いているので、全日本語話者が使うべき正しい日本語表記はプルリクウェストということになりますね! プルリクエストとかいたら間違いです!
GitLabフロー
GitHubフローに各種環境用のブランチを足したものがGitLabフローです。GitHubフローに従う、というfeatureブランチもとりあえずここで入れています。GitLabはSaaSでありつつも、OSSとしてバージョンを打ってリリースもしているため、その2つのリリース物件に対応するブランチ戦略になっています。
ブランチ | 役割 | 説明 | 分岐元 | マージ先 |
---|---|---|---|---|
main | 集積 | featureで作業した結果をマージ | なし | なし |
feature/x | 作業 | 機能の実装作業を行う | main | main |
stable/x | スナップショット | バージョンごとのブランチ | main | なし |
staging | 環境 | ここにマージするとstaging環境にデプロイ | main | pre-prod |
pre-prod | 環境 | ここにマージするとpre-prod環境にデプロイ | staging | production |
production | 環境 | ここにマージするとproduction環境にデプロイ | production | なし |
まとめ
Gitのブランチ戦略を考えるのは、なかなか頭を使う作業です。実際にどのようなコミットが行われるのか、デプロイ先は1つなのか? (SaaSとかの場合)、複数同時にリリース物件を管理する必要があるのか(RubyとかPythonみたいに複数のマイナーバージョンが同時にサポート対象にして管理しなければならない場合)とかの条件によっても変わってきます。今回の記事では戦略を考えるためのメタな「ブランチの役割」について考えてみあした。
また、今時のGitは基本分散リポジトリとして使うのではなくて、GitHubやGitLab上の中央集権で使うということで、それらのサービスの提供するブランチ保護機能も考慮した作戦立案が必要不可欠でしょう。あ、もちろん、GitHubやGitLabを使ってない人はそれらを考えずに自由に作戦を考えても良いと思います。僕の周りではこの2つ以外はもう最近は見かけないのでこれらを前提で考えています。
前回書いた2024年Gitワークフロー再考は、作業ブランチと集積ブランチだけに特化した、GitFlowの範囲内の話でした。ブランチの役割が変わればもちろん、いろいろ変わってきます。集積ブランチであれば直接コミット禁止にして、そこの中ではrebase禁止にしないと、フォークしたブランチのマージができない、ということになります。