ブランチ戦略考えてたら色んなフローのごちゃ混ぜ版ができた話

# TL;DR

![git2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108727/9155ac95-db35-f6f3-008f-e547f934f187.png)

なんと名付けよう・・・
もう既に名前が付いてたら誰か教えてください。
**Git Gocha☆Maze Flow** (^ω^)


# 問題領域

[Git-Flow](https://zenn.dev/ryo_4947123/books/497459787cb294/viewer/branchstrategy_gitflow)、[GitHub-Flow](https://zenn.dev/ryo_4947123/books/497459787cb294/viewer/branchstrategy_githubflow)、[GitLab-Flow](https://zenn.dev/ryo_4947123/books/497459787cb294/viewer/branchstrategy_gitlabflow)、近年では[Trunk-based](https://cloud.google.com/architecture/devops/devops-tech-trunk-based-development?hl=ja)など...
よく知られたブランチ戦略は色々あるけど、ウチの現場ではどれもフィットせず独自のモデルを考える必要があった。特に自分たちのケースで重要となったキーポイントが2つ。

### ①開発サイクルの違い

- 保守をメインとした比較的規模の小さい開発サイクル
- 新機能開発をメインとした大規模な開発サイクル

この2つが常に同時並行で進行しておりそれぞれ別のチームが担当しているため、これらを同期的に取り扱う必要がある。

### ②リリースの柔軟性

保守・新機能開発とも、機能ごとにリリース日の変更が頻繁に発生する。Git-Flowのような複数の機能（feature）を統合ブランチ（develop）上に積み重ねていくやり方は向かない。developに統合された特定のfeatureだけを先にリリースしたいという要求が発生した場合に詰む。

# ブランチモデル考察

### ①Git-Flow

Git-Flowをそのまま適用することは難しいが、Git-Flowをベースに複数のdevelopを作るパターンはアリだと思う。以下で語られている通り。

https://moznion.hatenadiary.com/entry/2017/01/07/135331

> ざっくり言ってしまえばリリースサイクルの違いです．例えば大きめの新機能を実装しつつ既存コードの保守もするという時，その時点で稼働しているコード (master) から派生したdevelop/A (便宜上Aとします) の上で新機能の実装を入れてしまうと，保守のコードと新機能コードが混ざってしまい，保守のためのデプロイのタイミングで出て欲しくない新機能のコードまで露出してしまうことになるので，それを防ぐ (分離させる) という目的でdevelopを複数に分ける (例えばdevelop/Bで新機能の開発は行なう) というような形にしています．

ただ、Git-Flowがただでさえ複雑な上、developが複数あるとさらにややこしい。
また、develop同士である程度リリースを分離できるとはいえ、featureレベルでリリース日をコントロールしたい場合にはこの方法ではやはり難しい。

### ②GitHub-Flow

保守メインの開発サイクルだけを考えれば一番合ってる。リリース計画も柔軟に変更しやすい。
ただ、masterが常にデプロイ可能な状態で本番環境と同期しているため、保守のための独立したステージング環境用のブランチは別で持っておきたい。
比較的規模の大きい新規開発までこれで回そうと思うと現状だとちょっとキツイ。

### ③Git-Feature-Flow

https://developers.gnavi.co.jp/entry/GitFeatureFlow/koyama

ここで紹介されている方法。あまりメジャーではないがイメージはこれに一番近い。
GitHub-Flowをベースにステージング環境と同期したブランチを用意するパターン。
ただ、やはり大規模開発だとこれだけだと少し心許ない。リリース作業に向けた専用の統合ブランチは欲しいところ。

### ④Trunk-based

・・・(^ω^)
日本でトランクベース開発が回せる現場って実際どれくらいあるんだろうなー

# ということで出来上がったのが

冒頭のコレ。

![git2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108727/9155ac95-db35-f6f3-008f-e547f934f187.png)

### 前提とルール
- 本番環境はmasterと同期している
- 新規開発用のステージング環境はreleaseと同期している
- 保守開発用のステージング環境はdevelopと同期している
- masterとdevelopはメインブランチとして常に存在しているがreleaseは使い捨て
- 機能開発は全てfeature上で行う
- masterへ入った変更は適宜他のreleaseやfeatureにも取り込む
### 新規開発のフロー
1. featureブランチをmasterから切り機能開発を行う
1. releaseブランチをmasterから切りリリースに必要なfeatureを統合していく<br>（リリース対象のfeatureが変更になった場合はreleaseブランチを切り直して再度必要なfeatureだけを統合する）
1. 統合後にreleaseブランチをレビューする
1. releaseブランチをmasterにマージする
### 保守開発のフロー
1. featureブランチをmasterから切り機能開発を行う
1. featureブランチをdevelopへマージしレビューする
1. リリース準備が整ったfeatureから順次masterにマージする

# 結果的に...

半分こじつけだけど（笑）、

- masterから直接feature切るあたりはGitHub-Flowっぽい
- masterが常にデプロイ可能な状態なのもGitHub-Flowっぽい
- featureをdevelopに入れてレビューに回すあたりはGit-Feature-Flowっぽい
- リリース準備に専用のブランチ使うあたりはGit-Flowっぽい

という感じで、GitHub-Flowのようなできるだけ軽量なモデルを維持してリリースの柔軟性を確保しつつ、常時平行して走る保守開発用にGit-Feature-Flowのエッセンスも取り入れ、比較的規模の大きい開発用にGit-Flowでいうreleaseブランチのような役割も考慮し・・・

という、色んなフローの要素をcherry-pickで寄せ集めてみました、みたいな形になった。^^;

### 問題点

特にdevelopブランチに入っているfeatureに依存関係があった場合にmasterにそれぞれのfeatureが反映されるタイミングが異なるので、本番環境と保守用のステージング環境で異なる挙動をする可能性がある。元のGit-Feature-Flowでは複数の環境に対応した統合ブランチを用意していたりレビューをmasterに限定したりすることで防いでいるように見えるが、このフローでは保守開発の環境に紐づいた統合ブランチがdevelop一本なのでそこが最大のデメリットか。
まぁそこは正直運用のシンプルさとトレードオフかな・・・