DevToolBox免费
博客

Git Rebase vs Merge:何时使用及为何重要

12 分钟作者 DevToolBox

理解 git rebasegit merge 的区别对每个 Git 开发者都至关重要。两个命令都将更改从一个分支集成到另一个分支,但方式截然不同。

Git Merge 的工作原理

Git merge 创建一个新的合并提交,它有两个父提交,合并两个分支的历史。原始分支历史被完整保留。

当你在主分支上运行 git merge feature 时,Git 找到共同祖先,创建合并提交,并推进主分支指针。

Git Rebase 的工作原理

Git rebase 重写历史,将你的分支提交移动到另一个分支的顶端。

当你从功能分支运行 git rebase main 时,Git 识别共同祖先,暂时移除你的提交,快进到 main 的顶端,然后逐个重新应用你的提交。

可视化对比

BEFORE (both branches have diverged from common ancestor C2):

          C5---C6---C7  (feature)
         /
  C1---C2---C3---C4     (main)

AFTER git merge feature (from main):

          C5---C6---C7
         /            \
  C1---C2---C3---C4----M8  (main) ← merge commit M8 has 2 parents
                            (feature still points to C7)

AFTER git rebase main (from feature):

  C1---C2---C3---C4                     (main)
                   \
                    C5'---C6'---C7'     (feature) ← new commits (different SHAs)

  Then fast-forward merge:
  C1---C2---C3---C4---C5'---C6'---C7'  (main, feature) ← linear history

功能对比

方面git mergegit rebase
历史保留所有历史 + 合并提交线性历史(无合并提交)
提交 SHA原始 SHA 保留创建新 SHA(重写)
安全性非破坏性(不重写历史)破坏性(重写提交历史)
冲突解决在合并提交中一次解决在重放期间可能逐次解决
团队友好对共享分支安全对共享分支危险
回退容易(回退合并提交)较难(查找原始提交)
git bisect合并提交可能干扰干净的线性历史有助于 bisect
图形可视化带分支的复杂图干净的单线

Git Merge 详解

快进合并

当目标分支没有新提交时,Git 可以简单地向前移动分支指针。

# Fast-forward merge (no merge commit created)
git checkout main
git merge feature

# Before:
# C1---C2 (main)
#        \
#         C3---C4 (feature)

# After:
# C1---C2---C3---C4 (main, feature)
# main pointer simply moved forward

三方合并

当两个分支都有新提交时,Git 执行三方合并。

# Three-way merge (creates merge commit)
git checkout main
git merge feature

# Before:
#        C3---C4 (feature)
#       /
# C1---C2---C5---C6 (main)

# After:
#        C3---C4
#       /       \
# C1---C2---C5---C6---M7 (main)  ← merge commit M7

--no-ff:始终创建合并提交

--no-ff 标志强制 Git 创建合并提交,即使可以快进。

# Force merge commit even when fast-forward is possible
git checkout main
git merge --no-ff feature

# Before:
# C1---C2 (main)
#        \
#         C3---C4 (feature)

# After (with --no-ff):
# C1---C2---------M5 (main)  ← merge commit preserves branch history
#        \       /
#         C3---C4 (feature)

# After (without --no-ff, default):
# C1---C2---C3---C4 (main, feature)  ← no evidence of branch

Git Rebase 详解

基本 Rebase

标准 rebase 将你的提交重放到目标分支之上。

# Basic rebase workflow
git checkout feature
git rebase main

# Before:
#        C3---C4 (feature)
#       /
# C1---C2---C5---C6 (main)

# After rebase:
#                     C3'---C4' (feature)  ← new commits!
#                    /
# C1---C2---C5---C6 (main)

# Then merge (fast-forward):
git checkout main
git merge feature
# C1---C2---C5---C6---C3'---C4' (main, feature)  ← linear!

交互式 Rebase

交互式 rebase 让你可以修改、压缩、重排或丢弃提交。

# Interactive rebase - clean up last 4 commits
git rebase -i HEAD~4

# Editor opens with:
pick abc1234 Add user model
pick def5678 Fix typo in user model
pick ghi9012 Add user validation
pick jkl3456 Fix validation edge case

# Change to:
pick abc1234 Add user model
fixup def5678 Fix typo in user model        # squash into previous, discard message
pick ghi9012 Add user validation
fixup jkl3456 Fix validation edge case      # squash into previous, discard message

# Result: 2 clean commits instead of 4
# "Add user model" (includes typo fix)
# "Add user validation" (includes edge case fix)

# Interactive rebase commands:
# pick   = use commit as-is
# reword = use commit but edit message
# edit   = use commit but stop for amending
# squash = meld into previous commit (keep message)
# fixup  = meld into previous commit (discard message)
# drop   = remove commit entirely

--onto Rebase

--onto 标志让你将提交子集 rebase 到不同的基础上。

# --onto: Move a branch to a different base
# Scenario: feature-b was branched from feature-a by mistake
#           You want feature-b based on main instead

#        D---E (feature-b)
#       /
# A---B---C (feature-a)
#     |
#     F---G (main)

git rebase --onto main feature-a feature-b

# Result:
#     D'---E' (feature-b)  ← now based on main
#    /
# A---B---C (feature-a)
#     |
#     F---G (main)

冲突解决

merge 和 rebase 都可能产生冲突,但体验不同。

Merge 冲突

合并时,所有冲突一次性呈现。

# Merge conflict workflow
git checkout main
git merge feature
# CONFLICT (content): Merge conflict in src/app.ts
# Automatic merge failed; fix conflicts and then commit

# 1. Open conflicting files and resolve
# 2. Stage resolved files
git add src/app.ts
# 3. Complete the merge
git commit  # creates merge commit with conflict resolution

# Abort merge if needed
git merge --abort

Rebase 冲突

Rebase 时,冲突可能在每次提交重放时出现。

# Rebase conflict workflow
git checkout feature
git rebase main
# CONFLICT in commit C3: Merge conflict in src/app.ts

# 1. Resolve conflict in src/app.ts
git add src/app.ts
# 2. Continue rebase to next commit
git rebase --continue
# May hit another conflict in C4...

# CONFLICT in commit C4: Merge conflict in src/utils.ts
git add src/utils.ts
git rebase --continue

# Abort rebase if it gets too complex
git rebase --abort  # returns to pre-rebase state

# Skip a problematic commit during rebase
git rebase --skip

团队工作流策略

基于 Merge 的工作流

最常见的团队工作流,完全使用 merge。

# GitHub Flow (merge-based)
git checkout -b feature/add-auth
# ... make commits ...
git push -u origin feature/add-auth
# Open PR on GitHub
# Review + approve
# Click "Merge pull request" (creates merge commit)
# Or "Squash and merge" (single commit)

先 Rebase 后 Merge 工作流

使用 rebase 更新功能分支,然后合并。

# Rebase-before-merge workflow
git checkout feature/add-auth
# ... make commits ...

# Before opening PR, update with latest main
git fetch origin
git rebase origin/main

# Force push (safe because it's your own branch)
git push --force-with-lease origin feature/add-auth

# Open PR on GitHub
# Merge with --no-ff to record integration point
git checkout main
git merge --no-ff feature/add-auth

Squash and Merge 工作流

将所有功能分支提交合并为单个提交。

# Squash and merge (via GitHub UI or CLI)
git checkout main
git merge --squash feature/add-auth
git commit -m "feat: add authentication system"

# Before:
# main: A---B---C
# feature: A---B---D---E---F---G

# After squash-merge:
# main: A---B---C---H  ← H contains all changes from D+E+F+G
# (feature branch can be deleted)

Rebase 的黄金法则

永远不要对已推送到共享远程分支的提交执行 rebase。

# DANGEROUS: Rebasing a shared branch
git checkout shared-feature
git rebase main
git push --force  # !! This rewrites history for everyone!

# SAFE: Rebasing your own local branch
git checkout my-local-feature
git rebase main
# No push yet, or push --force-with-lease to your own branch

# SAFE: Using --force-with-lease instead of --force
git push --force-with-lease origin my-feature
# Fails if remote has commits you haven't seen

最佳实践

Git Rebase vs Merge Best Practices:

1. Use merge for integrating feature branches into main
   - Creates clear integration points
   - Safe for shared branches
   - Easy to revert entire features

2. Use rebase to keep feature branches up-to-date
   - git rebase main (before opening PR)
   - Creates clean, linear history
   - Makes code review easier

3. Use interactive rebase to clean up before PR
   - Squash fixup commits
   - Reword unclear commit messages
   - Drop debugging commits

4. Use git pull --rebase as default
   - Avoids unnecessary merge commits
   - git config --global pull.rebase true

5. Never rebase shared/pushed commits
   - Only rebase your own unpushed work
   - Use --force-with-lease, never --force

6. Use squash-merge for feature branches
   - One clean commit per feature on main
   - Detailed commits preserved in PR history

7. Use --no-ff for important merges
   - Preserves the fact that a branch existed
   - Makes git log --first-parent useful

常见问题

何时应该使用 rebase vs merge?

使用 rebase 在开 PR 前更新本地功能分支。使用 merge 将功能分支集成到主分支。

rebase 危险吗?

Rebase 重写历史,对共享分支危险。对本地未推送的提交是安全的。

什么是 squash and merge?

将功能分支的所有提交合并为目标分支上的单个提交。

可以撤销 rebase 吗?

可以。使用 git reflog 找到 rebase 前的状态。

团队应该用 rebase 还是 merge?

大多数团队受益于混合方法:开发者在本地 rebase,然后 squash-merge 到主分支。

git pull --rebase 是什么?

git pull --rebase 获取远程更改并将本地提交 rebase 到其上,而不是创建合并提交。

相关工具和指南

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

{ }JSON Formatter

相关文章

Git Rebase vs Merge:何时使用哪个(图解对比)

理解 git rebase 和 merge 的区别。学习何时使用哪个,避免常见陷阱,掌握 Git 工作流。

Git 命令速查表:开发者必备命令大全

完整的 Git 命令速查表:涵盖配置、分支、合并、变基、暂存和高级工作流程。

Git 分支策略:GitFlow vs 主干开发 vs GitHub Flow

对比 GitFlow、主干开发和 GitHub Flow 分支策略。学习分支结构、合并工作流、CI/CD 集成,以及如何为你的团队选择合适的策略。