git merge 生成合并提交保留分叉历史,适合审计回滚;git rebase 重写提交哈希实现线性历史,适用于本地整理和pr前优化,但不可用于已共享分支。

git merge 会生成合并提交,历史分叉不可消除
执行 git merge 后,Git 会创建一个新提交(Merge Commit),它有两个父提交:一个是当前分支最新提交,另一个是被合并分支的最新提交。这个操作不改变任何已有提交的哈希值,只新增一个连接点。
常见错误现象:在 git log --graph 中看到 “Y” 形结构,比如:
A---B---C---M (main)
\ /
D---E (feature)
这种结构适合需要追溯“谁在何时把哪个功能合入”的场景,比如上线回滚、审计或跨团队协作。但缺点也很直接:日志里充斥着大量 Merge commit,尤其高频合入时,主干历史变得难以线性阅读。
git rebase 重写提交哈希,强制变直线历史
git rebase 不是“移动”提交,而是将目标分支上的每个提交依次复制、重新应用到基准分支顶端,生成全新哈希值的新提交(D'、E')。原始提交(D、E)依然存在,但不再被当前分支引用。
使用场景包括:
- 本地开发完成、准备推送前整理提交:压缩
fix typo、WIP等临时提交 - 同步远程
main的最新改动,避免后续合并引入无意义分叉 - 向公共分支 PR 前,让 reviewer 看到干净、递进的逻辑流
注意:一旦 git push 过的提交被 rebase,就必须用 git push --force-with-lease 覆盖远程,否则他人 git pull 会拉下两套冲突历史。
冲突处理方式完全不同,影响调试节奏
git merge 在合并阶段一次性比对两个分支全部差异,冲突集中爆发,解决完就生成一个 Merge Commit;而 git rebase 是逐个重放提交,在每个提交应用时都可能触发冲突——你得反复 git add + git rebase --continue,直到所有提交重放完毕。
这意味着:
- 如果 feature 分支有 12 个提交,且第 7 个引入了与 main 冲突的 API 修改,你会在重放第 7 个时卡住,必须解决后才能继续
- 无法跳过某个提交(除非
git rebase -i删除或编辑它),而merge没有这种“中途暂停”机制 - 冲突解决过程中的暂存状态容易误操作,比如忘记
git add就直接--continue,导致该提交丢失修改
pull 默认用 merge,但可全局设为 rebase
git pull 本质是 fetch + merge(或 rebase)。默认行为等价于 git pull --ff-only 或三方合并,但你可以用配置让它自动走变基流程:
运行 git config --global pull.rebase true 后,所有 git pull 都等效于 git pull --rebase。
不过要注意:
- 这个设置对已存在的本地提交无效,只影响后续 pull 行为
- 如果上游分支已被多人基于开发,你又开启了
pull.rebase,每次 pull 都可能触发重放+冲突,反而增加负担 - 团队协作中,不要强制要求所有人开启该配置,尤其当 CI/CD 流水线依赖特定提交哈希时
真正容易被忽略的是:变基不是“更高级的合并”,它只是不同目的下的历史整形工具。用错场景(比如对已共享的分支做 rebase)带来的协作成本,远高于多看几眼分叉历史的麻烦。











