教程
🛠️

开发工具

Git、VS Code、终端与效率工具使用指南。

Git 合并与变基:冲突来了别慌

搞懂 merge 与 rebase 的区别和取舍,学会读懂并解决合并冲突,掌握保持提交历史整洁的实用技巧。

· 更新于 2026-07-20 阅读量 --

协作时最常遇到的”惊吓”就是:合并冲突(conflict)。两条分支改了同一文件的同一处,Git 不知道听谁的,就把皮球踢给你。这一篇先把 merge 和 rebase 这对兄弟讲清,再手把手教你怎么拆冲突这个雷。

把冲突想成两个编辑同时改一句话:A 改成”今天晴天”,B 改成”今天下雨”,合并时总得有人拍板用哪句,Git 不会替你猜。

merge:保留真实的”分叉史”

git merge 会把两条分支的历史真正交汇成一个新的”合并提交”:

git switch main
git merge feature-x

优点是历史真实可溯——你能清楚看到某天某功能是从哪条分支合进来的。缺点是如果功能分支很多,历史图会变成一团乱麻(很多交叉的线)。

rebase:把历史”梳成一条直线”

rebase 的思路不同:它把当前分支的提交”摘下来”,先快进到目标分支最新处,再一颗颗重新接上去:

git switch feature-x
git rebase main
# 之后切回 main 再 merge,就会是干净的快进合并
git switch main
git merge feature-x

rebase 后历史变成一条漂亮的直線,没有多余的合并节点,review 时很清爽。但代价是它改写了提交历史(原来的提交被换成新哈希的新提交)。

merge 还是 rebase?一句话准则

  • 未推送的本地分支:想让历史干净,用 rebase
  • 已推送到远程、别人也在用的分支只用 merge,绝不 rebase——改写公共历史会让协作者崩溃。
  • 团队里常约定:“个人功能分支用 rebase 整理,合进 main 用 merge 保留轨迹。“

冲突长什么样

合并遇到冲突时,Git 会在文件里插入标记:

<<<<<<< HEAD(当前分支 main 的内容)
function hello() { return "你好"; }
=======(要合并进来的 feature-x 的内容)
function hello() { return "hello"; }
>>>>>>> feature-x
  • <<<<<<< HEAD======= 之间:你当前分支的内容。
  • =======>>>>>>> 之间:对方分支的内容。
  • 你的任务:删掉标记,留下正确的代码。

一步步解决冲突

# 1. 合并触发冲突后,先看哪些文件冲突
git status

# 2. 打开冲突文件,手动编辑,删掉 <<< === >>> 标记,保留正确内容
# 3. 改完后,把解决好的文件加入暂存区
git add 冲突文件.js

# 4. 所有冲突都解决完,提交这次合并
git commit

现代编辑器(如 VS Code)会提供”采用当前/采用传入/两端都保留”的按钮,点几下就能解决,比手改标记省事。

用工具辅助

# 图形化解决冲突(装了 VS Code 的话)
git config --global merge.tool vscode
git mergetool

遇到复杂冲突,git mergetool 会打开对比界面,左右两边分别是两个版本,中间是结果,直观很多。

常见新手坑

  • 看到冲突就 git merge --abort 溜了:能中止,但问题没解决,下次还得面对。勇敢拆掉标记才是正道。
  • rebase 已推送的分支:改写公共历史,队友 pull 时一团乱。记住”已公开的历史别 rebase”。
  • 解决冲突时把 <<<<<<< 标记也留进代码:提交后代码里出现奇怪符号,运行时报错。解决完务必确认标记全删了。
  • 冲突没全解决就 commitgit status 还有未解决的就提交,半截代码进库。

小测验

  • 问题1:merge 和 rebase 最大的观感区别?答案:merge 保留分叉交汇(有合并提交),rebase 把历史梳成一条直线。
  • 问题2:为什么已推送到远程的分支不建议 rebase?答案:rebase 改写提交历史(换哈希),会让协作者拉取时历史对不上。
  • 问题3:冲突标记 ======= 上下分别代表什么?答案:上是当前分支内容,下是要合入的分支内容。

更多实战:rebase 整理后再合并

你在本地的 feature-x 上提交了三次,期间 main 被同事推了两次新提交。你想让历史干净:

git switch feature-x
git rebase main        # 把你的三次提交"挪"到 main 最新之后
# 若有冲突,逐个解决后 git add + git rebase --continue
git switch main
git merge feature-x    # 此时是快进合并,没有多余合并节点

这样 main 的历史是一条直线,review 时清爽。记住:rebase 只用于你自己的、还没推送到远程的分支。

中止与后悔

git rebase --abort     # rebase 中途想放弃,回到操作前
git merge --abort      # 合并冲突搞不定,放弃这次合并

这两个命令是”逃生舱”,任何时候觉得乱了,先 abort 回到干净状态再想。

自测:你真的懂了吗

  • rebase 中途冲突解决了,下一步?答案:git addgit rebase --continue
  • 为什么已推送的分支别 rebase?答案:改写历史会让协作者拉取时对不上。
  • 合并搞砸了想放弃用?答案:git merge --abort

常见认知误区

合并与变基最容易被误解的是”该用哪个”。误区一是”为了历史干净无脑用 rebase”——却忘了 rebase 会改写提交历史(生成新哈希),如果那条分支已经推送到远程、别人也在用,你一 rebase 再强推,协作者拉取时历史就对不上了,轻则冲突重则混乱。铁律:已公开的远程分支只用 merge,本地未推送的分支才用 rebase 整理。误区二是”看到冲突就 panic”——冲突不是错误,只是 Git 把选择权交给你,按标记删掉不要的那段、留正确的即可。误区三是”rebase 中途卡住就放弃整条分支”——其实 git rebase --abort 能一键回到操作前的干净状态,随时能撤。误区四是”解决冲突时把 <<<<<<< 标记也留进代码”——提交后代码里出现奇怪符号,运行时才报错,解决完务必确认标记全删了。

这一篇你该记住的

  • merge 保留真实分叉史,rebase 把历史梳成直线但改写历史。
  • 准则:本地分支可 rebase 整理,已公开的远程分支只用 merge。
  • 冲突标记 <<<<<<< / ======= / >>>>>>> 三块,手动删标记留正确代码。
  • 解决流程:git status 看冲突 → 编辑文件 → git addgit commit
  • 善用编辑器按钮或 git mergetool 降低手改出错率。

下一篇我们讲 进阶救命命令:stash 暂存、cherry-pick 摘提交、reset 回退——这些是你偶尔”翻车”时的安全绳。