無料プレビュー 8 / 14

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 に乗せる定番

次のレッスンでは、合流時の事故 — コンフリクト をどう解消するか学びます。

参考リンク

全 14 レッスンを、登録なしで無料で読めます。