merge と rebase — 統合の 2 つの戦略
学習目標
このレッスンを終えると、次のことができるようになります。
- merge と rebase の違いを 1 枚の図で説明できる
- どちらをいつ使うべきかの判断基準を持てる
- fast-forward / 3-way merge / squash merge の違いを区別できる
merge と rebase は「同じゴールへの 2 つの道」
両方とも目的は同じ: ブランチ A の変更をブランチ B に取り込む。 だが、できあがる履歴の形が違う。
出発点
gitGraph
commit id: "A"
commit id: "B"
branch feature
checkout feature
commit id: "C"
commit id: "D"
checkout main
commit id: "E"
feature ブランチが C・D を作っている間に、main で E が起きた状況。
merge の場合
git switch main
git merge feature
gitGraph
commit id: "A"
commit id: "B"
branch feature
checkout feature
commit id: "C"
commit id: "D"
checkout main
commit id: "E"
merge feature id: "F: マージ commit"
特徴:
- 履歴がそのまま保存される (C・D・E がそれぞれ独立に残る)
- 新しく
Fという merge commit が作られる (枝が合流した記録) - 「いつ feature が main に合流したか」が後から見て分かる
rebase の場合
git switch feature
git rebase main # main の最新を土台に feature を作り直す
git switch main
git merge feature # この時点では fast-forward (枝なし合流)
gitGraph
commit id: "A"
commit id: "B"
commit id: "E"
commit id: "C'"
commit id: "D'"
特徴:
- 履歴が一直線になる (枝分かれが消える)
- C・D は新しい commit C'・D' に書き換えられる (ハッシュが変わる)
- 「枝が合流した」という事実そのものが消える
比較表
| 観点 | merge | rebase |
|---|---|---|
| 履歴の形 | 枝分かれが残る | 一直線になる |
| commit ハッシュ | そのまま | 書き換わる |
| 合流の事実 | merge commit に残る | 消える |
| 他人と共有済のブランチへ | 安全 | 危険 (他人の履歴が壊れる) |
| 適した場面 | チーム共有ブランチへの統合 | 自分のローカル feature を整える |
いつ merge / いつ rebase
merge を使う
feature/Xをmainに取り込む最終ステップ (Pull Request の merge)- 他人と共有しているブランチでの統合
- 「いつ合流したか」を記録に残したい
rebase を使う
- 自分のローカル feature ブランチを最新 main に追いつかせる
git switch feature/login git fetch origin git rebase origin/main # main の最新を土台に再構築 - 自分の WIP commit を整える (squash で 1 つにまとめる等)
- まだ push していない、または自分だけが使っているブランチ
rebase 黄金律
push 済の commit (他人が見たかもしれない commit) は rebase しない
なぜなら rebase はハッシュを書き換える。他人が古いハッシュ参照で作業していると、再 push したとき履歴が壊れる。
fast-forward merge — 一直線の場合
「main が C・D の地点から進んでいない」ケースでは:
gitGraph
commit id: "A"
commit id: "B"
branch feature
checkout feature
commit id: "C"
commit id: "D"
git merge feature すると 新しい merge commit を作らず、main のポインタを C・D の先端まで進めるだけ。これを fast-forward merge と呼ぶ。
gitGraph
commit id: "A"
commit id: "B"
commit id: "C"
commit id: "D"
「main = feature と同じ場所」になる。一直線で美しい。
fast-forward を禁止したい場合
「機能完成の合流地点」を必ず履歴に残したい時は:
git merge --no-ff feature
# → main が前進可能でも、わざと merge commit を作る
GitHub の Pull Request 設定で「Always create a merge commit」を選ぶとこれが既定動作になる。
squash merge — 複数 commit を 1 つに圧縮
gitGraph
commit id: "A"
commit id: "B"
branch feature
checkout feature
commit id: "C: WIP"
commit id: "D: WIP fix"
commit id: "E: 完成"
checkout main
merge feature id: "S: feat: ログイン機能 (圧縮)"
feature 上で WIP commit が 3 つあったが、main には圧縮した 1 つの commit として取り込む方法:
git merge --squash feature
git commit -m "feat: ログイン機能"
GitHub Pull Request では「Squash and merge」を選択。コンパクトな履歴を保ちたい時の定番。ailms でも個人 feature ブランチ → main は基本 squash。
3 つの merge 戦略 早見表
| 戦略 | 履歴 | 適した場面 |
|---|---|---|
| fast-forward | 一直線 | 自分専用ブランチ、cherry-pick で 1 commit だけ取り込み |
| 通常 merge (3-way) | 枝合流の commit が残る | 大きな feature の合流、develop ブランチがある場合 |
| squash merge | feature の commit が 1 つに圧縮 | レビュー単位の機能 PR (ailms 推奨) |
振り返り
- merge = 履歴を残す。共有ブランチへの統合に安全
- rebase = 履歴を一直線に整形。自分のローカルで使う。push 済には禁忌
- squash merge は「機能単位 1 commit」を main に乗せる定番
次のレッスンでは、合流時の事故 — コンフリクト をどう解消するか学びます。
参考リンク
- Pro Git「Rebase と Merge」: https://git-scm.com/book/ja/v2/Git-のブランチ機能-リベース
- GitHub「PR の merge 方法」: https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges
全 14 レッスンを、登録なしで無料で読めます。