Git 冲突怎么解决:别只删标记,先看懂暂存区的 1、2、3 阶段

Git 冲突最容易让人着急的,是工作区里那几行 <<<<<<<、=======、>>>>>>>。
我现在遇到冲突,反而会先停一下。那三段文字只是 Git 给你的待编辑结果,真正有用的信息还在暂存区里。
拿一个很小的例子说。当前分支和待合入分支都改了 config.yml 的同一行:
bash
git merge feature
# CONFLICT (content): Merge conflict in config.yml
这时先看状态:
bash
git status --short
# UU config.yml
git ls-files -u
UU 表示这个路径在两个方向都没有自动合上。后一个命令会列出同一路径的三条记录,末尾的数字就是 stage:
text
100644 <blob> 1 config.yml
100644 <blob> 2 config.yml
100644 <blob> 3 config.yml

这三个版本不是抽象概念,直接能拿出来看:
bash
git show :1:config.yml # 两个分支分开前的共同祖先
git show :2:config.yml # 当前分支 HEAD,也就是 merge 的当前侧
git show :3:config.yml # 正在合入的那个分支
我觉得这比只盯着冲突标记靠谱得多。比如配置里的端口和运行模式都被改了,先看共同祖先,才知道每一边究竟改了哪一项。否则手动拼出来一个"看着都保留了"的文件,可能已经把本来互斥的配置混在一起。
确认目标内容后,编辑工作区里的 config.yml,把冲突标记删干净。然后不是直接 commit,而是先把它标记为已解决:
bash
git add config.yml
git merge --continue
git add 在这里的意思不是"暂存一点改动",而是告诉 Git:这个路径不再保留三份未合并版本,工作区当前这份就是最终结果。
有个常见误区是冲突一出现就跑 git reset --hard。如果只是这次 merge 不想要了,语义更准确的是:
bash
git merge --abort
Git 官方手册也提醒过,merge 开始前如果工作区就有未提交改动,abort 不一定能把所有现场完整还原。所以准备合分支前先把自己的改动提交或临时存起来,这一步真能少掉很多后悔。
最后说一个不该被神化的小工具。长生命周期分支反复和主干对齐时,同一种冲突确实会反复出现,可以开启 rerere:
bash
git config rerere.enabled true
它会记录第一次冲突的自动合并结果和你手工修好的结果。下一次再次出现同样的冲突前像时,Git 可以把之前的解析应用到工作区。
但这不是"以后不用看冲突了"。复用出来的结果仍然要看 diff、跑测试,再 git add。同一段文本冲突,业务含义可能已经变了。
本文命令语义按 Git 2.47.3 的 git-merge 与 git-rerere 官方手册核对。