
Git の merge と rebase の使い分け - 履歴の形・黄金律・やり直し方
「merge と rebase、結局どっちを使えばいいの?」——Git で必ずぶつかる疑問です。両者は最終的な中身は同じでも、履歴の形が変わります。違いと使い分け、そして「やらかした時の戻し方」を、Git 公式ドキュメントを一次ソースに整理します。
根本的な違い: 履歴の形
- merge: 2つのブランチをマージコミット(親が2つの特殊なコミット)で統合する。分岐した作業の痕跡がそのまま履歴に残る
- rebase: 自分のコミットを相手ブランチの先端に付け替え(再適用)し、直線的な履歴にする。元コミットは破棄され新しいコミット(別のSHA)が作られる
最終的なファイルの中身(スナップショット)は両者で同じです。違うのは到達するまでの履歴の見え方だけです。
[分岐した状態]
C4 (feature)
/
C1-C2-C3 (main)
[git rebase main(feature 上で実行)= 直線的]
C1-C2-C3-C4' (feature)
[git merge feature(main で実行・分岐ありなら)= マージコミット]
C1-C2-C3---M (main) ※ M は C3 と C4 を親に持つ
\ /
C4fast-forward / --no-ff / squash
| 種類 | 挙動 |
|---|---|
| fast-forward | 分岐が無ければポインタを進めるだけ(マージコミットなし) |
--no-ff | 進められる場合でも必ずマージコミットを作る(GitHubの「Merge pull request」がこれ) |
| squash | 複数コミットを1つに押し潰して追加(GitHubの「Squash and merge」) |
--no-ff は「このブランチがあった」事実を履歴に残せます。squash は履歴を綺麗にできますが、個々のコミットの作者・日時が失われ、同じブランチを使い続けると衝突しやすくなります。
rebase の黄金律
WARNING
公開済み(共有済み)のコミットを rebase してはいけません。 rebase は元コミットを破棄して別SHAのコミットを作り直します。他人が元のコミットを取り込んだ後に rebase して force push すると、相手の履歴と同じ内容が重複して混乱します。安全なのはローカル未pushのコミットだけです。
公式(Pro Git)も「リポジトリ外にあり、他人が基に作業しているコミットを rebase するな」と明記しています。
interactive rebase で履歴を整える
PR を出す前の「コミット掃除」に最適なのが git rebase -i です。
git rebase -i HEAD~5エディタで各コミットに操作を指定します。
| コマンド | 効果 |
|---|---|
pick | そのまま採用(既定) |
reword | メッセージだけ書き換え |
squash | 直前と統合(メッセージは結合) |
fixup | 直前と統合(自分のメッセージは破棄) |
drop | 削除 |
行の並べ替えでコミット順も変えられます。コミットメッセージの整え方はConventional Commitsも参考に。
コンフリクト処理の違い
# 衝突を解決したら
git add <file>
git rebase --continue # 次のコミットへ
git rebase --abort # 中止して元に戻すgit add <file>
git commit # マージコミットを作成
git merge --abort # 中止merge は基本1回の解決で済むのに対し、rebase はコミットごとに衝突が起こりうるのが大きな違いです。コミットが細切れだと「コンフリクト地獄」になりがちで、先に squash してから rebase すると楽になります。
git pull --rebase
git pull は既定で merge するため、取り込むたびにマージコミットが増えがちです。--rebase を使うと、自分のコミットをリモート先端に付け替えて履歴を直線的に保てます。
git pull --rebase
git config --global pull.rebase true # 常に rebase で取り込むNOTE
公式は pull --rebase を「潜在的に危険なモード」とも表記しています。未push のローカルコミットに対してなら安全ですが、公開済みコミットの上では履歴の書き換えになる点は同じです。
やり直し方(ここが安心材料)
rebase / merge を「しくじった」時も、たいてい元に戻せます。
git reset --hard ORIG_HEAD # rebase/merge/reset 直前の状態へ(1手前のみ)git reflog # HEAD の移動履歴(HEAD@{n})
git reset --hard HEAD@{3} # n番目の状態に戻すORIG_HEAD は直前の1操作分しか覚えていないので、複数操作を挟んだら reflog(既定で履歴を一定期間保持)を使うのが確実です。進行中なら --abort で安全に中断できます。
使い分けの指針
| 場面 | 推奨 |
|---|---|
| main など共有ブランチへの統合 | merge(履歴を残す・安全) |
| PR前のローカル整理・最新取り込み | rebase(直線的に) |
| PRの取り込み方 | チーム方針で merge / squash / rebase を統一 |
考え方として、merge は「何が起きたかの記録」、rebase は「どう作ったかの物語」を残す、と捉えると選びやすいです。
まとめ
- merge は分岐を残す、rebase は直線的にする。最終的な中身は同じ
- fast-forward / --no-ff / squash でマージの履歴の残り方を選べる
- 公開済みコミットの rebase は厳禁(force push で他人の履歴を壊す)
rebase -iで squash / fixup / reword。PR前の掃除に有効- 失敗しても
ORIG_HEAD/reflog/--abortで戻せる - 共有は merge、ローカル整理は rebase が基本線
「中身は同じ、変わるのは履歴の形」と「共有ブランチは rebase しない」——この2点を押さえれば、merge / rebase の判断でもう迷いません。


