Squash Merge とは

PR をマージする際、PR 内の全コミットを1つのコミットにまとめて main に入れる方式。

通常マージとの比較

通常マージ(Create a merge commit)

PR 内の作業コミットがすべて main に入る。

main:
  abc1234 Merge pull request #94
  def5678 fix: テストのモック戻り値を修正
  ghi9012 refactor: 引数を構造体に統一
  jkl3456 feat: リトライ機構を追加 (#91)

Squash Merge

PR ごとに1コミットになる。

main:
  abc1234 refactor: 引数を構造体に統一 (#94)
  jkl3456 feat: リトライ機構を追加 (#91)

メリット

  • main の履歴が PR 単位になり、途中の試行錯誤(typo 修正、レビュー対応等)が見えない
  • git log main が読みやすい
  • git bisect で問題コミットを探すときも PR 単位で絞れる

落とし穴:派生ブランチで差分が混入する

Squash Merge では新しいコミットハッシュが生成される。そのため、未マージのブランチから別ブランチを切ると問題が起きる

発生条件

main ─── A
          └── branch-1 (PR #1) ─── B ─── C
                                          └── branch-2 (PR #2) ─── D

PR #1 を Squash Merge すると、main には B+C をまとめた新コミット BC' が入る。

main ─── A ─── BC'  (新しいハッシュ)

branch-2: A ─── B ─── C ─── D  (元のハッシュのまま)

branch-2 の PR には B, C, D の差分が表示される。Git は BC'B+C が同じ変更だと認識できない。

対策

  • 新ブランチは常に最新の main から切る
  • やむを得ず派生した場合は git rebase origin/main で解消できる

GitHub での設定

Repository Settings → General → Pull Requests で以下を選択可能:

  • Allow merge commits(通常マージ)
  • Allow squash merging(Squash Merge)
  • Allow rebase merging(Rebase Merge)

複数有効にしてPRごとに選ぶことも、1つだけに絞ることもできる。

まとめ

Squash Merge は main の履歴をきれいに保つ良い選択。ただし「新ブランチは必ず main から切る」というルールとセットで運用すること。