第一次在编辑器里看到一行 <<<<<<< HEAD 时,很多新人都会有一种身体被掏空的感觉:是不是我哪条命令写错了?是不是整个项目要重新拉一遍?代码是不是已经全毁了?
坦白说,这不是程序崩溃,也不代表你的工作出了大问题。这是 Git 在合并(merge)分支时,碰上了一个它没法替你拿主意的 merge conflict(合并冲突),于是把决定权原封不动地交到了你手上。那一串尖括号和 HEAD,不是系统在骂你,而是 Git 在文件里画了一个路标:这里有两份都对不上的代码,到底留谁,你来说了算。
这篇文章就围绕这个让无数新人当场破防的瞬间展开,我会从冲突标记怎么读、冲突怎么产生,到第一次实战怎么处理,再到我这些年见过的各种奇葩冲突现场,完整过一遍。不管你是刚学 Git 的新手,还是已经被冲突折磨过几轮的准老手,这篇都值得读完。
1. 屏幕变成战场:<<<<<<< HEAD 出现的那一秒发生了什么
1.1 先看懂那段“乱码”到底在说什么
先别慌,我们看一眼真实的冲突标记长什么样。
假设我正在 feature/login 分支上做登录功能,同事在 main 分支上改了同一个文件 index.js。两边都在同一段代码附近做了改动,Git 自动合并失败,于是我打开文件,看到的可能是这样:
javascript复制function init() {
// 这里开始冲突
<<<<<<< HEAD
console.log("登录模块初始化,加载用户信息");
userStore.fetch();
=======
console.log("初始化用户数据,包含历史记录");
historyStore.load();
>>>>>>> main
renderPage();
}
看起来像乱码对吧?其实每一段都有含义:
<<<<<<< HEAD到=======之间:是你当前所在分支(也就是 HEAD 指向的分支)里的内容。=======到>>>>>>> main之间:是你要合并进来的那个分支(这里叫main)里的内容。- 最后的
>>>>>>> main:标记着第二个版本结束,main就是对方分支名。
换句话说,Git 没有删掉你的任何代码,它把你这边的版本和对方那边的版本都完整地放在了同一个文件里,用分隔线隔开,逼你做个选择。
在 VSCode 里,这部分会显示成 "Current Change" 和 "Incoming Change" 两个可点击的选项,还会给你 “Accept Current Change”(保留当前分支的)、“Accept Incoming Change”(保留合并进来的)、“Accept Both Changes”(两个都保留)这类快捷按钮。但在命令行、Sublime、或者没有装插件的编辑器里,你看到的就是最原始的尖括号文本。
1.2 新人崩溃的真正原因不是标记本身
我见过不少新人,遇到这种情况第一反应是“代码坏了”,然后直接找组长说“项目被我搞崩了”。
这其实是误解。你看到的不是报错,而是 Git 给你留的一道“选择题”。冲突意味着 Git 已经尽力把两边改动都拼在一起了,但有一处或者多处改动,它实在没法判断取舍——因为两个分支在同一个位置写了不一样的内容。这时候它不能擅自决定,否则很容易把某个人的逻辑悄悄丢掉,所以只能停下来,等你人来裁决。
所以,<<<<<<< HEAD 不是“死神的宣告”,更像是 Git 贴的便利贴:这几个地方我拿不准,你确认一下。
真正让新人崩溃的,是那种“不知道怎么处理”的无助感。因为学校里教的 Git 流程通常都是 add、commit、push 一条龙,很少有老师真的带你撞一次冲突。第一次面对这种满屏尖括号的文件,谁都会怀疑人生。我当年第一次看到这东西,第一反应也是把文件关掉,想重新 clone 仓库。
但问题就在这里:冲突不会因为你重新 clone 就消失。你重拉一遍,合并该冲突还是冲突。只有学会处理它,才算真正开始用 Git 协作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 冲突是怎么来的:Git 合并的本质和“三个版本”的博弈
2.1 HEAD 是什么?它为什么出现在冲突标记里
要理解冲突,先得认识 HEAD。
在 Git 里,`HEA
