讲解

当两个分支修改了同一文件的同一区域,merge 就无法自动裁决,进入冲突状态。此时 Git 会做的事是:把冲突文件改写成带标记的形式,暂停合并流程,把决定权交给你。别怕冲突——它不是错误,只是 Git 在说「这里需要人来定夺」。git status 会列出所有 unmerged 状态的文件。

打开冲突文件,会看到这样的结构:<<<<<<< HEAD 到 ======= 之间是当前分支的内容,======= 到 >>>>>>> 分支名 之间是对方分支的内容。解决方式就是手动编辑这个区域:保留一边、保留另一边、或者融合两者,然后把 <<<<<<<、=======、>>>>>>> 三行标记全部删掉。所有冲突文件都改完后,git add 标记它们为已解决,最后 git commit 完成合并(合并提交的信息 Git 已经备好,直接用即可)。

如果冲突太复杂想反悔,git merge --abort 随时可以把仓库恢复到合并前的状态,什么都没发生。减少冲突的实务经验:功能分支命短一点(拖得越久和主线岔得越远);频繁把主线的更新合进(或 rebase 进)功能分支,小冲突随时解,别攒到最后;同一文件的格式化改动和功能改动分开提交。

示例

制造并解决一个真实冲突:

git switch -c feature
printf '版本:feature\n' > version.txt
git add version.txt
git commit -qm "feat: feature 版本"
git switch main
printf '版本:main\n' > version.txt
git add version.txt
git commit -qm "feat: main 版本"
git merge feature --no-edit || echo "==> 发生冲突,需要手动解决"
git status --short
printf '版本:main + feature 合并版\n' > version.txt
git add version.txt
git commit -qm "merge: 解决 version.txt 冲突"
git log --oneline --graph -3

再演示「不玩了」的退路——--abort:

git switch -c left
echo "左边的写法" > conflict.txt
git add conflict.txt
git commit -qm "feat: 左边"
git switch main
echo "右边的写法" > conflict.txt
git add conflict.txt
git commit -qm "feat: 右边"
git merge left --no-edit || echo "==> 又冲突了"
git merge --abort
git status --short

abort 之后工作区干干净净,和合并前一模一样。

常见坑

  • 忘记删冲突标记就提交:<<<<<<< 被原样提交进仓库的事故屡见不鲜。解决后全文搜一遍 <<<<<<< 和 >>>>>>>,确认没有残留。
  • 解决冲突时把一方的改动整个丢掉:急着「让它能跑」只保留了自己的版本,队友的功能被静默覆盖。逐处理解两边意图再合并。
  • add 之后忘了 commit:冲突文件 add 完合并还没结束,要再 commit 一次才真正完成。git status 会提示 All conflicts fixed but you are still merging。
  • 在慌乱中乱删文件:任何时候 git merge --abort 都能无损退出,先冷静下来再说。

小结

冲突 = 同一处被两边修改,手动编辑标记区域 → add → commit 完成合并;--abort 是无损退路。勤合并、短分支能显著减少冲突。下一章开始和远程仓库打交道。