はじめに
前回記事にて、Git ブランチ戦略を考える上で衝突しがちな観点のトレードオフや、戦略選定時に意識したい視点について整理・考察していきました。
それらを踏まえ、今回の記事では弊社のS.Kさんが考案してくれた「Clean-history GitFlow」戦略についてご紹介していきたいと思います。
この戦略の大まかな特徴は以下の通りです。
- GitFlow, GitFeatureFlow の思想がベース
- タスク管理と連動した作業ブランチ
- 少ない安定ブランチ数での運用
- 最小限のルールで綺麗な履歴を維持できる
個人的には、多くの実務案件で通用するポテンシャルの戦略だと思っているので、興味のある方はぜひ戦略選定時の選択肢に加えてみていただきたいです。
シリーズ記事
Clean-history GitFlow 戦略の概要
ブランチの運用ルール
ブランチの種類
Clean-history GitFlow(CGF)は、以下4種のブランチで運用します。
- 本番用:production
- 開発統合用:develop
- 機能開発用:feature
- 緊急修正用:hotfix
develop, feature ブランチは、開発におけるタスクと一致します。
※ タスク管理には相応のツールを利用することになるかと思いますので、
各タスクにはIDなどの識別子が付与されている前提の運用です。
そのため、develop ブランチは「常に1本だけ存在する長命ブランチ」ではなく、
「特定のカテゴリで作業ブランチを統合するための使い捨てブランチ」という位置付けになります。
複数の機能を並行開発するようなプロジェクトでは、develop ブランチも複数同時に並走することになるイメージ
たとえば、バックエンド側で「ブログ記事の管理機能を開発する」というタスクがあるとすると、これが親タスク(= develop)になります。
さらにこの親タスクを実装用に分解していくと、以下のようになるかと思います。
- 記事マスタテーブルの作成(その他、タグや筆者テーブルなども必要に応じて作成)
- ブログ記事情報登録APIの作成
- ブログ記事一覧取得APIの作成
- ブログ記事情報取得APIの作成
- ブログ記事情報更新APIの作成
- ブログ記事情報削除APIの作成
これらが子タスク(= feature)に該当し、作業ブランチの単位となります。
各ブランチの役割・運用ルール
| ブランチ種別 | 役割 | 命名規則 | マージ先 | 禁止事項 | 削除タイミング(★) |
|---|---|---|---|---|---|
| production | ・本番リリース用のメインブランチ ・develop/hotfixからのPRのみマージ可 |
production |
- | ・直コミット ・force push |
- ※ ブランチルールなどで保護しておくと◎ |
| develop | ・開発統合 ・親タスク単位 |
develop/{該当タスクID}例)develop/task001 |
production | ・直コミット ・develop間のマージ |
マージ直後 |
| feature | ・機能開発(作業ブランチ) ・子タスク単位 |
feature/{該当タスクID}例)feature/task002 |
develop/hotfix | - | マージ直後 |
| hotfix | ・緊急修正(リリース情報ごと) ・親タスク単位 |
hotfix/{該当タスクID}例)hotfix/task003 |
production | ・直コミット | マージ直後 |
★ ブランチの削除は、ブランチマージ後にレビュイーが実施
フロー図
1. 基本的なフロー
開発時の基本的なフローは以下の通りです。
- production ブランチから親タスクである develop ブランチを切る
- 作成した develop ブランチから、子タスク単位で feature ブランチを切る
- feature ブランチにて実装
- feature -> develop となる PR を作成、レビュー
- approve された PR を develop ブランチにマージ
- develop -> production となる PR を作成、レビュー
- approve された PR を production ブランチにマージ(= リリース)
feature -> develop の PR でコンフリクトが発生した場合は、develop からの逆マージ/ rebase にてコンフリクトを解消します。
個人的には、
- PRレビューを依頼する前なら「rebase 対応もOK」
- PRレビュー依頼後なら「逆マージ対応のみ」
とした方が、「実装者の開発体験を維持しつつも、レビュアーに不要な負荷をかけない」場合が多いと考えています。
PRレビューを依頼した後に rebase で対応すると:
既存のレビューコメントが「過去のコミット」に紐づくため、レビュアー側で差分や指摘の前提を追い直す必要が出てくる
develop からの逆マージで対応すると:
既存のレビューコメントの文脈を保ったまま、「コンフリクト解消分の差分」として変更内容を確認できる
ただし、ここまで細かい内容を運用ルールとして設けるべきかは、
プロジェクトとして目指すメンバーのブランチ運用スキルや実際のチームの状況によると思います。
どちらにせよ、「レビュイーとレビュアーの間でしっかりコミュニケーションをとること」が大前提
2. 緊急修正時のフロー
緊急修正時も基本の流れは同じですが、
develop の代わりに hotfix を親タスク用ブランチのプレフィックスとして使用します。
親タスク用ブランチのプレフィックスを開発時と明示的に分けているのには、
履歴上で「何を緊急修正として対応したか」をわかりやすくする他、
「コミュニケーション時の齟齬を起きにくくする」という目的があります。
例)
「今リモートに上がっている develop/aXve8g ブランチがマージされるまで、他のdevelopの対応を〜」
より
「今リモートに上がっている hotfix/aXve8g ブランチがマージされるまで、他のdevelopの対応を〜」
の方が「何故その対応を優先したいのか」などの意図が明確なため、コミュニケーションがスムーズです。
また、ランダム文字列的なタスクIDだったとしてもプレフィックスが異なるため、
ブランチを取り違えるなどの人的ミスの発生確率が格段に低くなります。
3. 並行開発時のフロー
複数の develop ブランチを並行して開発する場合も、基本のフローは同じです。
ただし、「それぞれの develop ブランチは依存関係を持たず、独立性を保つ必要がある」という認識は事前にチームで共有しておく必要があります。
また、develop -> production の PR でコンフリクトが発生した場合は、rebase を用いてコンフリクト解消を行います。
理由は、この時点での PR はコードレビューではなく、
「feature ブランチで行った対応が期待通り反映されているか」を最終確認する場であり、
原則「レビューバック対応は発生しない」ためです。
そのため、ここでは「履歴の追いやすさ」を優先します。
並行開発では「他の develop ブランチの対応内容が前提となる機能開発」を行うケースもあるかと思います。
その場合は、以下の流れで対応します。
- 前提機能を持つ develop ブランチ(develop/001)から、対応する develop ブランチ(develop/002)を切る
- 基本フロー同様、develop/002 ブランチから feature ブランチを切って実装を進める
- develop/001 ブランチが production ブランチへマージされたら、develop/002 ブランチの切り元を production ブランチに rebase する
- 以降は基本フローと同じ
4. 検証環境利用時のフロー
staging などの検証環境を用意することで、開発資材の品質を担保する機会を運用フローに組み込むことができます。
検証環境用ブランチは「履歴を意識する必要がない」構成をとっているため、feature, develop, hotfix どのブランチからでもマージが可能です。
検証環境用ブランチは「検証専用」であり、他のブランチの起点として利用する想定はしていません。
検証環境を利用する際の手順は、以下の通りです。
- 検証環境用のブランチに移動
- production ブランチの最新コミットまで reset する
git reset --hard origin/production- ※ 検証環境用ブランチは履歴を残さない前提のため、
reset --hardを用いた運用を採用
- 検証したいブランチをマージ
並行開発時も、手順としては同様です。
最新の production ブランチの状態に戻してから、検証したい資材を積んでいくイメージです。
常に production が起点となるため、検証後に staging を元に戻す、といった後片付け作業は必要ありません。
この運用であれば、以下のようなケースにも柔軟に対応することができます。
- develop/001 と develop/002 ブランチの内容をまとめて動作検証したい
- →「検証したいブランチをマージ」で上記ブランチを順にマージ
- 意図的に production ブランチの古いコミットを再現したい
- → reset 時に該当コミットのハッシュを指定
なお、ここでは検証環境として staging ブランチを例に挙げていますが、
実際に運用する場合は複数の検証環境が必要になるかと思います。
たとえば、
- dev-verification:開発用の共有環境
- staging:リリース前のQA用環境
など。
プロジェクトの規模によっては、並行開発に備えて開発用の共有環境を複数用意するケースもあるかもしれませんね。
プルリクエストの運用ルール
PR は作成元のブランチ種別に応じてマージの種類を使い分けることで、
開発時の履歴意識を最小限にしつつ、プロジェクトとしては綺麗な履歴が維持できる構成としています。
また、PR タイトルにも一定の命名ルールを設けることで、PR を見た時に「どの種類の PR か」が視覚的にわかりやすくなるようにしています。
PR の承認条件はプロジェクト規模や方針、メンバースキルに応じて適宜調整します。
| マージ先 | マージ元 | マージ方法(★) | PR タイトルの形式 | 承認条件(例) |
|---|---|---|---|---|
| develop または hotfix | feature | Squash and merge (以降、スカッシュマージ) |
{子タスクID} {作業概要}例:「qte4bFy ブログ記事一覧取得APIの作成」 |
2名以上からの approve |
| production | develop | Create a merge commit (以降、デフォルトマージ) |
[dev]{親タスクID} {機能概要}例:「[dev]qte49gR ブログ記事管理機能の追加」 |
2名以上からの approve ※ 内1名は最終レビュー担当メンバーの誰か |
| production | hotfix | Create a merge commit(デフォルトマージ) |
[hotfix]{親タスクID} {修正概要}例:「[hotfix]6hP3nvx ロール変更時のブログ記事更新バグを修正」 |
1名以上からの approve |
★ PR のマージは、承認条件達成後にレビュイーが実施
上記の運用ルールに則ると、develop/hotfix のコミットが feature の対応と1対1になるため、「どの対応で何をしたのか」がとても追いやすくなります。
この運用を実施した際の Git グラフは、最終的に以下のようなイメージになります。
CGF 戦略の利点と留意点
利点
1. 柔軟性が高く、拡張・カスタマイズに強い
CGF は「絶対に守らなければならない」運用ルールが少なく、「要所の判断を人間に委ねる余地が大きい」戦略でもあります。
これは「運用ルールだけではスムーズに回らない」という意味ではありません。
むしろ「最低限のルールを守っていれば、開発が円滑に回せる」という前提に立ちつつ、
「何故そのルールがあるのか」という目的を理解できていれば、運用の「例外」を作ることなく
「状況に応じたアプローチを許容できる」戦略であるとも言えます。
また、CGF では
- develop および hotfix ブランチは使い捨て前提の中長期ブランチ(= 長命ブランチではない)
- feature ブランチは常に短命、かつ実装タスク単位
- production ブランチが唯一の絶対基準として存在
という構造があるため、「どのブランチを長命にするか」「どこを絶対基準にするか」といった運用ルールを変更することで、他のブランチ戦略に寄せることができます。
例)
develop ブランチを1本固定の長命運用にする
→GitFlow 寄り
develop ブランチを省略し、「production - feature」ブランチの関係にする
→トランクベース 寄り
もし CGF がニーズに合わなくなってきたと感じ始めたら、運用を「他の戦略に寄せたルールに変更」していき、
最終的には「よりプロジェクトにマッチしたブランチ戦略に完全に移行」という段階を踏めます。
「今までと全く異なる戦略にいきなり切り替えなくてはならず、現場が混乱する」という要素が少ないため、
プロジェクト規模の拡張などにも柔軟に対応することができます。
とはいえ、CGF 自体が「立ち上げ〜中規模プロジェクト」までをカバーできる拡張性の高い運用だと考えているため、よほどプロジェクトが大規模化しない限りは、ブランチ戦略の見直しが必要になることはないと思います。
2. 安定ブランチの数が少ない
人間が常に意識して守るべきブランチは、基本的に production ブランチのみです。
先に述べている内容になりますが、
- develop ブランチは中長期の使い捨て
- 検証環境用ブランチは reset 前提の運用
であるため、これらのブランチの履歴を管理する必要はありません。
これは実務において、かなり大きいメリットだと思います。
また、検証環境においては「ローカルで発生しない環境依存のトラブルシューティング対応などを気軽に反映することができる」という強みにもなります。
reset 前提なので履歴が残らないばかりか、最悪、検証環境が「意図せぬ挙動が頻発するような壊れ方」をしたとしても「起点を戻せばいいだけ」
→「どうせ消す」という前提で動けるので、調査や検証の初動が迅速
さらに言うと、上記のようなケースでは運用ルールの目的を理解できている人であれば、
検証環境用ブランチを「マージ前に毎回 production ブランチの最新コミットまで戻す必要がない(= 一連の検証時は前進対応でOK)」という判断もできますし、それを実行したとしてもルール違反にはなりません。
上記は CGF の柔軟性の高さをよく表している例とも言えますね。
3. シンプルな構成で、品質を担保するフェーズを明確に切り出せる
利点①でも触れていますが、CGF では「production ブランチが唯一の絶対基準として存在」します。
また、develop ブランチは互いに依存関係を持たないため、「それぞれの目的単位で独立している」とも言えます。
メインブランチである production ブランチ以外との依存性を排除する設計のため、ブランチ間の依存関係が最小化される
→ 並行開発時でも互いの開発内容に影響されない
実務的な利点としては、
- リリース調整が容易
- 並行開発時の検証フェーズが互いに独立する
という観点が挙げられます。
CGF では「production ブランチへのマージ = リリース」となります。
そして develop ブランチごとに独立しているため、develop ブランチ間の開発開始時期などの前後関係に依存しません。
そのため、「develop/001 を先にリリースしようと思っていたけど、優先度の高い差し込みタスクである develop/002 の対応を先にリリースしよう」などの調整が容易に行えます。
リリース待機状態にあるブランチは、production ブランチにマージをしなければOK、というシンプルな構成
もちろん、リリース日程調整などで待機ブランチが出てきたとしても、develop ブランチを分けてしまえば良いだけなので、開発そのものが止まってしまう、といったリスクも避けられます。
これは検証環境も同様で、履歴を管理しない検証環境は develop ブランチの前後関係に依存していないため、
「Aの検証フェーズが完了しないとBの検証フェーズが開始できない」というような長期的な開発タスク停滞の発生を避けることができます。
検証環境を複数の並行開発機能で共有していたとしても「専有期間」を事前に決めておけば、検証フェーズについてもある程度並行して進めることが可能
例)
時間で区切る
→ 午前中はAの検証を行い、午後はBの検証を行う
日で区切る
→ 今日はAの検証、明日はBの検証。それぞれ終わらなかった分は明後日以降で適宜相談の上、検証環境を専有する
4. 実装時の開発体験を維持しつつ、綺麗な履歴を保てる
CGF では、以下を前提とした運用により「実装時の自由度」と「最終的に残る Git 履歴の見通しやすさ」の分離を実現しています。
- feature ブランチでは、実装中の試行錯誤や細かい修正をそのままコミットしても良い
- develop / hotfix ブランチに取り込む際に、スカッシュマージによって「タスク単位の履歴」にまとめる
これにより、実装者は「後で履歴が汚れること」を過度に意識する必要がなくなり、実装に集中できます。
一方で develop や hotfix、そして production ブランチには「意味のある粒度の履歴」だけが残ります。
実装者目線で開発しやすいコミット粒度と、レビュー・リリース時に求められる履歴粒度は必ずしも一致しない
→ CGF では、このズレを「実装時の意識」ではなく、「ブランチと PR 運用」で吸収する
実務的には、以下のような利点があります。
- PR レビュー時は「このタスクで何をしたのか」が一目で把握できる
- production ブランチの履歴から、過去のリリース内容や変更意図を追いやすい
- 不具合発生時の原因調査において、「どのタスクが起因か」が特定しやすい
また、CGF では develop / hotfix ブランチが使い捨てであるため、「途中経過の履歴を将来に渡って残す必要がない」という割り切りができます。
このため、
- 実装フェーズではスピードと柔軟性を優先
- 統合フェーズでは可読性と追跡性を優先
という役割分担が明確になり、多くの運用で直面する「開発体験を犠牲にして履歴を綺麗にする」「履歴を犠牲にしてスピードを出す」といったトレードオフを、チームで意識的に抱え込む必要がなくなります。
「実装時の開発体験」と「プロジェクトとしての履歴の綺麗さ」という観点に対して、どちらも犠牲にしないバランスのとれた戦略でもある
留意点
1. 運用意図を理解した Git 履歴の読み取りが前提となる
CGF は、Git の操作や履歴構造に対して、「ある程度の理解があること」を前提としたブランチ戦略です。
たとえば、
- コンフリクト解消における rebase と 逆マージ の使い分け
- PR 種別におけるデフォルトマージとスカッシュマージ の使い分け
- 「この履歴は残すべきか」「残さなくて良いか」の判断
- 検証環境用ブランチが履歴を持たない前提であること
といった点は、運用意図を理解していないと混乱を招きやすい部分でもあります。
この辺りは CGF の利点と表裏一体の部分でもあるため、「意図が共有されていれば、ルールを増やさずに運用できるポイント」とも言えますね。
また、Git 操作として求められているのは、単にコマンドを知っているかどうかではなく、
”なぜその操作を行うのか” ”どのような影響があるのか”を「理解した上で判断できる」ことです。
目安として、CGF で開発メンバーに求められる Git のスキル感は、以下のように整理できます。
中級者レベル
- ローカルブランチで
resetやrebaseを自由に使える - リモートブランチへの影響をリスクとして理解しており、自分一人での操作に不安がある場合は確認やフォローを求めることができる
- 「危険だから触らない」ではなく、「危険性を理解した上で慎重になれている」状態
上級者レベル
- リモートブランチに対しても
resetやrebaseを適切に扱える - 履歴を書き換えることの影響範囲を把握し、目的に応じて最適な操作が選択できる
いずれのレベルにおいても前提となるのは、
リスクを理解した上で、自分が「何をしたいからその操作を選ぶのか」を説明できることです。
基本的に、CGF の開発メンバーには上記の「中級者レベル」が求められます。
新規参画者についても、この水準までなるべく早く到達してもらわないと「判断が特定の人に集中 = 属人化の要因」を招きやすくなります。
なお、理想としては「全員が上級者レベルに到達し、誰でも本番リリースに関わる操作を担える状態」を目指すのが望ましいでしょう。
ここでの「本番リリースに関わる操作」は、
developからproductionへのマージ- 上記に伴うコンフリクト解消
を想定しています。
そのため、新規参画者や Git に不慣れなメンバーがいる場合、最初のうちはフォローが必要になる場面が出てくる可能性もあります。
ただし、これは CGF が「難しい戦略」という意味ではありません。
- なぜこの運用をしているのか
- どこが厳密で、どこに裁量があるのか
といった方針を事前に明文化しておくことで、フォロー側に過度な負担をかけることなくスムーズに運用することができます。
こうした点で、CGF は「ルールを増やさなくても回せる代わりに、意図の共有が重要になる戦略」とも言えます。
2. 自由度の高さは、目的理解があって初めて成立する
CGF は柔軟性の高いブランチ戦略ですが、その自由度は「どこでも自由に判断して良い」という意味ではありません。
CGF では、
- 検証環境用ブランチを毎回 production ブランチの最新に戻さず、前進対応で検証を進める
- feature ブランチの履歴を綺麗に保つことより、開発体験を優先する
といった判断が、「個人の裁量として許容される」側面があります。
これらに共通しているのは、
- 影響範囲が一時的であること
- 最終的に production ブランチには、個人裁量の対応が残らないこと
- reset など、やり直せる手段がルールの中にあること
です。
一方で、「チームとして統一するべき、運用の前提となるルール」も存在します。
これの最たる例が、 PR のマージ種別の選択です。
PR のマージは、production ブランチに「恒久的に残る履歴の形」を決定します。
ここで個人の判断がバラつくと、
- 履歴の粒度が揃わない
- タスクとコミットの対応関係が崩れる
- 「なぜこの履歴になっているのか」を後から説明できなくなる
といった問題が発生します。
そのため、PR におけるマージ種別の選択は「個人単位での自由な判断が許容される」箇所ではなく、
「チームとして統一しなければならないルール」として位置付けられます。
PR のマージ種別の選択は「作業効率の話」ではなく、
「プロジェクトとして、何を履歴として残したいか」を決める行為
CGF における自由度とは「目的を理解した上での裁量」であり、
「目的が共有されていない状態での自由」ではありません。
この認識を、チーム全員で共有しておく必要があります。
3. 判断を人に委ねる場面が多く、属人化の余地がある
先にも述べている通り、CGF は柔軟性が高く「要所の判断を人間に委ねる余地が大きい」戦略でもあります。
これは大きな利点である一方、運用の仕方によっては「判断が特定の人に集中する」というリスクも内包しています。
というのも、ベースとして CGF では中級者以上の Git スキルが求められます。
そしてそれらは、
- 今どのフェーズなのか
- どこまでが一時的な影響で、どこからが恒久的な影響か
- この判断が、後続の開発や検証にどう影響するか
といった文脈理解を前提としています。
そのため、これらの判断を「分かっている人だけが行う」状態が続くと、
- 特定のメンバーに確認が集中する
- 「その人がいないと進められない」作業が増える
- 判断の背景が共有されず、再現性のない運用になる
といった、属人化の問題が発生しやすくなります。
ここで重要なのは、「ルールを増やすこと自体は悪ではない」ということです。
たしかに CGF は「絶対に守らなければならない」運用ルールが少なく、それにより高い柔軟性を確保しています。
そして、「開発体験の良さ」は「運用ルールの数」とトレードオフになる側面があることも事実です。
だからこそ、こうした副次的な要素は「成熟度に応じて外せるフェールセーフ」のルールとして設計します。
本質的に「判断を人に委ねる余地が大きい」戦略だからこそ、そのチームが「ルールに則っていれば開発が円滑に進む」状態にするために「判断を補助するルール」を設けるのは、むしろ望ましい選択
→ こうした「うちのチームでは」が通用するのが、CGF の柔軟性の高さでもある
ただし、「フェールセーフ」としてのルールは、基本的に「恒久対応」としては設定せず、
- なぜ必要なのか(守るものは何か)
- どの段階で廃止できるのか(どの状態をゴールとするのか)
といった内容をチームで共有し、「チームとして目指す成熟度」を意識できるようにしておくのが良いと思います。
意図のわからない(伝わらない)ルールは、将来的に「単なる制約」になる可能性が高い
「属人化があるから」ではなく、「属人化リスクに対するフェールセーフの置きどころを段階的に調整するため」に
「ルールを増やす/減らす」という視点で考えていけるとスムーズかと思います。
反対に、恒久的なフェールセーフについては、「人に依存するルール」ではなく「仕組み化」で解決するべきだと考えています。
(この点については、次回以降のシリーズ記事で取り上げる予定のため、今回はこれ以上深掘りしません)
なお、フェールセーフ的なルールとして設定しないとしても、「判断を人に閉じない」運用をしていく意識は必要だと思います。
- 「なぜその判断をしたのか」を言語化する
- 判断基準を都度チームに共有する
- よく出てくる判断は、ガイドラインとして明文化する
といった工夫をすることで、「目的理解があって初めて成立する自由度」を「個人ではなくチーム全体に広げていく」ことができます。
4. 検証環境を共有する前提が、意識から抜けやすい
検証環境が「チームで共有するもの」であることは、CGF に限らず、多くのブランチ戦略で共通している点かと思います。
しかし、CGF は各ブランチの独立性が高く、
- 開発単位が明確に分かれている
- 他のブランチの進捗や状態に依存せずに作業できる
といった特徴があります。
この性質は大きな利点である一方、検証フェーズにおいては「検証環境もまた共有リソースである」という意識が、相対的に抜けやすくなる側面があります。
以下のようなケースは、CGF で意識していないと起こりやすいポイントとして挙げられます。
- 自分の検証を優先するあまり、他の検証との衝突に気づかない
- 検証中であることが暗黙になり、他メンバーが状況を把握できない
- 誰かの検証が終わるのを待つ必要があるが、確認が取れず作業が止まる
特に、即時にコミュニケーションが取れる相手ばかりではないチーム構成の場合、
「確認待ち」がそのまま開発の停滞につながる可能性もあります。
そのため CGF を採用する場合は、
- 検証を開始・終了したことをどう共有するか
- 検証環境を一定期間専有する場合の扱い
- 確認が取れない場合にどう判断するか(待つ/切り上げる/巻き戻す)
といった点を、事前にチームで整理しておくことが必要になります。
検証環境は「衝突しないように設計するもの」ではなく「衝突しうる前提で、どう動くかを共有しておくもの」
→これをチームの共有認識として持てているかどうかで、運用の安定性やスピード感が大きく左右される
CGF は、検証環境の衝突を「ブランチ構成によって強制的に解決する」戦略ではありません。
だからこそ、検証フェーズにおいては「ブランチの独立性」と「環境の共有性」を切り分けて考える必要があります。
5. PR 運用の設計次第で、CGF の性格が変わる
CGF はブランチ構成だけを見るとシンプルな戦略ですが、実際の運用においては「PR の扱い方までを含めて、初めて性格が決まる戦略」でもあります。
というのも、PR のマージによって残る Git 履歴は、
- 一度残ると基本的に消えない(恒久的)
- 将来の調査・レビューなどの判断材料になる
- 後から「なぜこうなっているのか」を説明できる状態にしておくべき
といった性質を持っています。
つまり PR のマージは、「今の作業を楽にするための操作」ではなく、「プロジェクトとして、どんな履歴を将来に残したいか」を決める行為でもあります。
そのため CGF においては、「どのマージ方法を使うか」は単なる好みや効率の問題ではなく
「戦略全体の“性格”を左右する設計ポイント」として捉える必要があります。
5-1. スカッシュマージ運用前提の CGF は、バランスが取りやすい選択肢
本記事で紹介している CGF では、
- feature -> develop / hotfix はスカッシュマージ
- develop / hotfix -> production はデフォルトマージ
という PR 運用を前提としています。
この構成は、
- 実装時の操作は feature ブランチに閉じ込める
- 統合ブランチ以降には「タスク単位の履歴」だけを残す
- production ブランチの履歴を、リリース単位で追いやすくする
という点で、「開発体験と履歴の可読性のバランスが取りやすい」運用だと考えています。
ただし、これが「絶対のルール」というわけではありません。
5-2. PR 運用はトレードオフであり、カスタマイズの余地がある
「PR 種別ごとにマージ方法を使い分ける」という運用は、履歴の表現力が高い一方で「人的ミスが発生しやすいポイント」でもあります。
- 実装者がマージ方法の選択を間違える
- レビュー時にそこまで意識が回らず、選択されているマージ方法の確認が漏れる
- なぜそのマージ方法を選んだのかが共有されない/例外として許容するしかない
といったケースは、珍しくありません。
そのため「すべての PR をデフォルトマージに統一」して、よりシンプルな PR 運用を採用した CGF 運用も、十分に選択肢になりえます。
これは CGF の自由度を、「あえて制限するカスタマイズ」であり、 CGF を否定するものにはなりません。
ただし、この選択は「最終的に残る履歴の綺麗さ」とのトレードオフです。
シリーズ記事の中で既に触れている内容になりますが、履歴の綺麗さは単なる開発者の好みではなく「情報としての履歴の価値を高めるもの」です。
この点について、言ってしまえば CGF の性格を変えるのは「PR のマージ方法を変更するだけ」なので、いつでも切り替えることができてしまいます。
しかし、ここを変えるのは「プロジェクト全体に関わる運用方針を変更すること」であり「例外を作ること」でもあります。
あまり気軽に変えるものではない、ということは理解しておくべきでしょう。
ルールで縛るか、仕組みで支えるか
個人的には、PR 運用の複雑さについては、
- ルールを増やして人に覚えさせる
- 判断を個人の注意力に委ねる
よりも、
- ブランチ保護
- PR テンプレート
- CI によるチェック
といった「仕組み化」でフォローする方が健全だと考えています。
これは、先に述べた「恒久的なフェールセーフは仕組みで吸収する」という考え方にも通じる箇所でもあります。
おわりに
いかがでしたでしょうか。
今回は、CGF(Clean-history GitFlow)のブランチ戦略について、その考え方や運用イメージ、採用する上での留意点を整理してみました。
CGF は、「こうしなければならない」を多く強制する戦略ではありませんが、同時に「何も考えずに使えば良い」戦略でもありません。
PR 運用を含めて「どこまでを厳密に定め、どこに裁量を残すのか」を意識して設計することが、CGF を「自分たちの戦略」とするために重要となります。
この記事で CGF を知っていただき、今後の開発の選択肢として加えてみていただければと思います。
次回は、開発からリリースまでの流れをより具体的に整理し、実際に運用する際の解像度を高めていけるようにしていく予定です。
以上です。最後まで閲覧いただきありがとうございます。