rebase と merge の議論はGitワークフローで最も一般的なものの1つです。両コマンドはあるブランチの変更を別のブランチに統合しますが、根本的に異なる方法で行います。それぞれをいつ使用するかを理解することが、クリーンなプロジェクト履歴の維持に不可欠です。
Git Merge の仕組み
Git merge は両ブランチの履歴を結びつける新しい「マージコミット」を作成します。完全な履歴とコミットの時系列を保持します。
git merge feature を実行すると、Gitは共通の祖先を見つけ、両方の変更を組み合わせた新しいコミットを作成します。
A---B---C feature
/ \
D---E---F---G---H main (merge commit)
$ git checkout main
$ git merge featureGit Rebase の仕組み
Git rebase はコミットを別のブランチの上に移動(「リプレイ」)します。コミット履歴を書き換えて線形のシーケンスを作ります。
feature ブランチで git rebase main を実行すると、各コミットを一時的に外し、mainの最新に合わせ、コミットを1つずつ上に再適用します。
Before rebase:
A---B---C feature
/
D---E---F---G main
After rebase:
A'--B'--C' feature
/
D---E---F---G main
$ git checkout feature
$ git rebase mainビジュアル比較
╔═══════════════════════════════════════════╗
║ MERGE RESULT ║
║ ║
║ D---E---F---G---H main ║
║ \ / ║
║ A---B---C feature ║
║ ║
║ ✓ Preserves all commits ║
║ ✓ Shows merge point ║
║ ✗ Non-linear history ║
╚═══════════════════════════════════════════╝
╔═══════════════════════════════════════════╗
║ REBASE RESULT ║
║ ║
║ D---E---F---G---A'--B'--C' main ║
║ ║
║ ✓ Clean linear history ║
║ ✓ Easy to read ║
║ ✗ Rewrites commit hashes ║
╚═══════════════════════════════════════════╝Merge を使うべき場面
- 公開/共有ブランチ——Mergeは履歴を書き換えないので安全。
- コンテキストの保持——マージコミットが統合タイミングを示す。
- チームコラボレーション——複数人が同じブランチで作業する場合。
- リリースブランチ——正確な統合ポイントを保持。
# Merge with merge commit (recommended for main)
$ git checkout main
$ git merge --no-ff feature
$ git push origin mainRebase を使うべき場面
- featureブランチ(mainへマージ前)——クリーンな線形履歴を作成。
- 最新状態の維持——マージコミットなしで新しい変更を取得。
- PR送信前——リベース済みのクリーンなコミットはレビューしやすい。
- ローカルコミットの整理——インタラクティブリベースで圧縮・並べ替え・編集。
# Update feature branch with latest main
$ git checkout feature
$ git rebase main
# If conflicts occur, resolve them, then:
$ git add .
$ git rebase --continueインタラクティブRebase:squash、fixup、並べ替え
インタラクティブrebase(git rebase -i)はGitで最も強力な機能の1つです。
$ git rebase -i HEAD~4
# Editor opens:
pick a1b2c3d Add user authentication
pick e4f5g6h Fix typo in auth
pick i7j8k9l Add password validation
pick m0n1o2p Fix lint error
# Change to:
pick a1b2c3d Add user authentication
fixup e4f5g6h Fix typo in auth # merge into previous, discard message
pick i7j8k9l Add password validation
fixup m0n1o2p Fix lint error # merge into previous, discard message
# Result: 2 clean commits instead of 4
# Commands:
# pick = use commit as-is
# squash = merge into previous commit, keep message
# fixup = merge into previous commit, discard message
# reword = use commit but edit message
# drop = remove commit entirelyゴールデンルール:公開ブランチは絶対にRebaseしない
プッシュ済みで他の人が使っているブランチをrebaseしてはいけません。コミットハッシュが変わり、他の開発者が困ります。
ゴールデンルール:共有リモートにプッシュされていないコミット、または自分だけが作業しているブランチのみrebaseする。
# ❌ DANGEROUS: Rebasing a shared branch
$ git checkout main
$ git rebase feature # NEVER do this!
# ✅ SAFE: Rebasing your own feature branch
$ git checkout my-feature # only I work on this
$ git rebase main # safe!
$ git push --force-with-lease origin my-featureMerge vs Rebase:完全比較
| 基準 | Merge | Rebase |
|---|---|---|
| History | Non-linear, preserves branches | Linear, clean |
| Commit hashes | Preserved | Changed (new hashes) |
| Conflict resolution | Once (in merge commit) | Per commit (may resolve multiple times) |
| Traceability | High (merge commit shows context) | Medium (linear but no branch info) |
| Safety | Safe (no history rewrite) | Risky (rewrites history) |
| For shared branches | ✅ | ❌ |
| For personal branches | ✅ | ✅ |
| Reversibility | Easy (git revert) | Harder (requires reflog) |
| git bisect | Harder (non-linear) | Easier (linear history) |
一般的なGitワークフロー
フィーチャーブランチワークフロー
featureブランチを作成→開発→mainにrebase→--no-ffでマージ。
$ git checkout -b feature/login
# ... develop ...
$ git rebase main # clean up history
$ git checkout main
$ git merge --no-ff feature/login # merge with commit
$ git branch -d feature/loginGitflowワークフロー
develop、feature、release、hotfixブランチを使用。長寿命ブランチ間は常にmerge。
# Always merge between long-lived branches
$ git checkout develop
$ git merge --no-ff feature/login
$ git checkout release/1.0
$ git merge --no-ff develop
$ git checkout main
$ git merge --no-ff release/1.0
$ git tag v1.0トランクベース開発
短命なfeatureブランチ(1日以内)。頻繁にrebase、素早くマージ。
# Short-lived branch, rebase often
$ git checkout -b fix/typo
# ... quick fix ...
$ git rebase main
$ git checkout main
$ git merge fix/typo # fast-forward
$ git push危険なシナリオ
| シナリオ | リスク | 予防策 |
|---|---|---|
| Rebase main/master | Everyone's history breaks | Never rebase main |
| Rebase shared feature branch | Collaborators face divergent history | Use merge for shared branches |
| git push --force | Overwrites remote changes | Use --force-with-lease instead |
| Wrong conflict resolution during rebase | Code loss or corruption | Review each conflict, use git rebase --abort to restart |
| Rebase branch with merge commits | Merge commits flattened, confusing | Use --rebase-merges or avoid |
よくある質問
rebaseを元に戻せますか?
はい。git reflogでrebase前のコミットハッシュを見つけ、git reset --hardで復元できます。
featureブランチの更新にはrebase?merge?
自分だけが作業しているならrebase。他の人も使っているならmerge。
git pull --rebaseとは?
マージコミットを作らず、ローカルコミットをリモート変更の上にリプレイします。
プッシュ済みブランチをrebaseするとどうなる?
force pushが必要になります。旧コミットを取得済みの人は問題に直面します。
squash mergeとrebase + squashは同じ?
結果は似ていますが仕組みが違います。GitHubのsquash mergeは全コミットを1つに。rebase -iは選択的に圧縮できます。
OSSコントリビューションにはどちら?
ほとんどのOSSプロジェクトはリベース済みのクリーンなコミットを好みます。