導入
こんにちは、GxPの土田です。
この記事はグロースエクスパートナーズ Advent Calendar 2025 2枠目の6日目です。
チーム開発において、プルリクエスト(以下PR)を出してから承認しマージするまでは多少のラグがあります。
しかし、開発者はその間に座禅を組んで待っているわけにもいかないため、多くの場合はPRのマージを待たずに次の実装へと移ります。
結論は主題の通りですが、「やめろぉぉそのPRをマージするなぁぁぁぁぁ」という経験が何度かあり、「承認下りたらとっととマージしろ」派閥に真っ向から対抗すべく、本記事の執筆に至りました。
以下では、実例とともにその理由を解説していきます。
※注意:この記事にはブランチ運用に関する個人的見解が多分に含まれます。100%正しいとは限らないため、一意見としてお受け取りください。
典型例
次のような場合を考えます。
- 機能Aを開発するブランチ
feature/Aをmainブランチから切る - 機能Aの実装が終わったので、
main <- feature/AのPRを出す - 機能Aに依存する機能Bを実装したい
- 機能Bを開発するブランチ
feature/Bをfeature/Aから切る
- 機能Bを開発するブランチ
- 機能Bの実装が終わったのでベースブランチに向けて
feature/A <- feature/BのPRを出す - 機能Bの承認が先に下りる
最終的には、
main
└─ feature/A
└─ feature/B
のようにPRが連なります。
この時、feature/A <- feature/B のPRはマージすべきでしょうか?
原則
結論はNoです。
PR一覧画面には次のようなPRが並んでいることでしょう。
| Title | Branch | Review |
|---|---|---|
| 機能Aの実装 | main <- feature/A |
|
| 機能Bの実装 | feature/A <- feature/B |
Approved |
ここで feature/A <- feature/B のPRをマージすると、確かにPR一覧画面はスッキリします。
しかし、マージを行ってしまうとマージ先のブランチ feature/A には、機能A+機能Bの両方が混在することになります。
つまり、main <- feature/A のPRでは、機能Aと機能Bの両方の実装が差分として表示されることになります。当初意図していたのは「機能Aの実装」だけであるにもかかわらず、実態は「機能Aと機能Bの実装」になるわけです。
これではPRタイトルで嘘をついており、差分も嵩みレビューのしづらいPRが出来上がってしまいます。
よって feature/A <- feature/B に承認が下りたからと言ってすぐにマージはせず、main <- feature/A のPRがマージされるのを待ってからマージすべきなのです。
これが「PRは根元からマージすべき」ということです。
もちろん、前提としてこのようにPRが連なる状態は、全体の状況把握がしづらくなるため可能な限り避けるべきです。
例外
この原則には例外があります。
例えば次のような場合、
- 機能Aを開発するブランチ
feature/Aをmainブランチから切る - 機能Aの実装が終わったので
main <- feature/AのPRを出す - 機能Aにバグが見つかったが対応する時間がないため他の人に修正を依頼する
- 機能Aのバグ修正用ブランチ
bugfix/Aをfeature/Aから切る
- 機能Aのバグ修正用ブランチ
- バグ修正が終わったのでベースブランチに向けて
feature/A <- bugfix/AのPRを出す - バグ修正の承認が先に下りる
この場合は、
main
└─ feature/A
└─ bugfix/A
| Title | Branch | Review |
|---|---|---|
| 機能Aの実装 | main <- feature/A |
|
| 機能Aのバグ修正 | feature/A <- bugfix/A |
Approved |
のようにPRが連なります。
この事例では、feature/A <- bugfix/A を先にマージすべきです。
前述のように根元を先にマージすると、「バグった状態の機能A」が main ブランチへとマージされることになります。デフォルトブランチに対して不完全なものをマージするのはできる限り避けるべきです。(壊れた状態でCIが走ったり、壊れた状態のデフォルトブランチから他の開発者がブランチを切ったりする可能性があるため。)
逆に feature/A <- bugfix/A を先にマージする場合、前述のようなPRタイトルで嘘をつくことにはなりません。なぜなら「バグった機能A + 機能Aのバグ修正 = 機能Aの実装」であるからです。
こちらを先にマージすることで、main ブランチには機能Aの完全なものを届けることができます。また、レビュー時にもバグったものではなく完全な実装を見てもらえるという利点があります。
まとめ
例外はあれど基本方針はシンプルです。
依存関係のあるPRが連なった場合、常に根元から順にマージをする。
以上が「プルリクエストは根元からマージせよ」の原則です。
補足
ちなみにGitHubでは、PRをマージした際には「Delete branch」ボタンが表示され、ブランチを削除すると後続PRのマージ先が自動的に切り替わります。そのため手動でベースブランチを切り替える必要はありません。
前述の
main
└─ feature/A
└─ feature/B
の例では、main <- feature/A をマージし feature/A ブランチを削除することで、feature/A <- feature/B のPRが路頭に迷わないように、feature/A ブランチがマージされた先(main)にマージ先が切り替わります。
これを利用する(または手動で切り替える)ことで、
main
└─ feature/B
という状態になります。
よって、先の原則は次のように言い換えることができます。
依存関係のあるPRが連なった場合、常に根元のブランチのみをマージする。
以上、混沌としたブランチ運用へ投じる一石でした。