合并冲突卡住时,先不要直接打开文件改 <<<<<<< 标记。先用 git status 看清哪些路径处于未合并状态,再判断当前处在 merge、rebase 还是 cherry-pick:这三种操作里 ours 和 theirs 指向的分支不一样,版本取反比改错代码更难回退。多数“改完又冲突”的情况,原因在于选错了要保留的一方,或者把锁文件、生成文件当源码手动合并。
Git 冲突要先分层定位:工作区的冲突标记、索引里 stage 1/2/3 的条目、尚未完成的合并提交、以及 .gitattributes 和 merge driver 配置。建议先用git diff --name-only --diff-filter=U列出未合并路径,逐条确认成因后再改;改完用git diff --check加一次完整构建验证,提交前保留git merge --abort这条回头路。
Git合并冲突先定位在哪一层
冲突不是一处,是四层。改错层的典型表现是:文件里标记删干净了,git status 还提示未合并;或者提交完成后发现整个文件被替换成了对方的版本。按下面四层依次确认,能避免在同一处反复折腾。
- 工作区层:文件里出现
<<<<<<< HEAD与>>>>>>>标记。检查位置是git diff -- path/to/file输出的冲突块。 - 索引层:
git ls-files -u是否列出 stage 1(base)、2(ours)、3(theirs)条目。只要有输出,就说明该路径还没git add。 - 提交层:
git status首行显示 “You have unmerged paths” 或 “All conflicts fixed but you are still merging”;ls .git/MERGE_HEAD存在说明在合并中,.git/rebase-merge存在说明在 rebase 中。判断依据不同,退出命令也不同。 - 配置层:
git check-attr -a path/to/file看 .gitattributes 是否给该文件指定了 merge 策略,git config --get merge.conflictstyle看你能否看到 base 段。
Git合并冲突:先看这四个位置
下面这段可以直接复制到仓库根目录执行,用来把状态、未合并路径和冲突成因一次看清;把示例路径换成实际文件即可。
# 1. 当前处于什么状态(merge / rebase / cherry-pick)
git status -sb
ls .git/MERGE_HEAD .git/rebase-merge .git/rebase-apply 2>/dev/null
# 2. 哪些路径还没合并完
git diff --name-only --diff-filter=U
git ls-files -u
# 3. 让冲突块带上 base 段,便于判断改了什么
git config merge.conflictstyle zdiff3
# 4. 只看引入冲突的提交
git log --merge -p -- path/to/file
- 日志:
git reflog -20找回冲突前的 HEAD;git log --merge -p -- path/to/file只看冲突双方的提交差异,比翻全量历史快。 - 命令输出:
git status -sb的短格式里,UU表示双方都改、AA表示双方都新增、DU/UD表示一边删除一边修改。这两个字母分别对应 ours 和 theirs。 - 配置项:
git config --get merge.conflictstyle、git config --get core.autocrlf、git check-attr -a path/to/file。行尾和 merge 策略引起的“整文件冲突”基本都在这三项里露头。 - 面板字段:IDE 的 Source Control 面板里,“Current (ours)” 与 “Incoming (theirs)”、Merge Editor 顶部的分支名、文件列表里的 U 标记。面板只反映索引状态,判断仍需回到
git status核对。
Git合并冲突:按可能性从高到低排除
按出现频率往下排,每条给出确认动作,确认不了就不要动手改。

- 同一区域被双方修改(最常见)。确认:
git diff -- path/to/file看冲突块两侧是否都含实质逻辑。处理:保留正确逻辑,删掉三行标记和 base 段,再git add path/to/file。 - ours / theirs 记反,在 rebase 和 cherry-pick 中尤其容易。确认:
git status首行是 “rebase in progress” 还是 “You have unmerged paths”;rebase 时 ours 是上游基底,theirs 才是你的提交,和 merge 相反。处理:不要用git checkout --theirs .批量覆盖,逐个文件比对后再git add。 - 行尾或编码差异导致整文件冲突。确认:
git diff --stat显示几乎整个文件都在冲突,git diff --ignore-all-space后差异大幅减少,file path/to/file看编码是否一致。处理:统一 .gitattributes(例如* text=auto),不要靠手动改几千行。 - 锁文件与生成产物冲突,如 package-lock.json、yarn.lock、构建输出目录。确认:
git status里出现这类路径。处理:取一边后重新执行安装或构建生成,再git add,不要手写合并。 - 重命名或删除与修改相撞。确认:
git status显示 “deleted by us / added by them”。处理:先确认该文件是否还需要,需要就git add保留,不需要就git rm。
这里最容易踩的坑是把 git checkout --ours <file> 当成“保留我的改动”的万能命令。它在 merge 里确实指当前分支,但在 rebase 里指上游基底,执行后你的提交内容会被整体丢弃,而且这一步不进 reflog 之外的历史。批量覆盖前先 git stash push -u 或建一个备份分支。
Git合并冲突:改完怎么确认真的解决了
验证分三步,都在仓库根目录执行:

# 1. 是否还有冲突标记残留或空白错误
git diff --check
git grep -n '^<<<<<<< '
# 2. 索引里是否还有未合并条目
git status
git ls-files -u
# 3. 提交后确认是合并提交(应输出两个父提交哈希)
git show --pretty=%P -s HEAD
git diff --check 无输出、git grep 搜不到标记、git ls-files -u 为空,才算索引干净;git status 应停在 “All conflicts fixed but you are still merging”,此时再 git commit 完成合并。
文件能打开不等于冲突解决了。建议合并提交后跑一次完整构建和与该文件相关的测试用例,确认行为符合预期;合入主分支后再看一次 CI 流水线是否通过。观察时长按项目节奏定,通常至少覆盖一次完整构建加一次代码评审,不要只看本地能否启动。
回滚要按阶段选命令,并且先保住现场:
- 还没提交:merge 用
git merge --abort,rebase 用git rebase --abort,回到冲突前状态。 - 已提交但没推送:先
git branch backup-merge留底,再git reset --hard ORIG_HEAD。这条命令会丢弃工作区未提交改动,执行前确认没有要留的内容。 - 已经推送:用
git revert -m 1 <merge-commit>生成反向提交,不要 force push 改写公共历史。后续若要重新合入同一分支,需要先 revert 掉这次 revert,否则该分支的改动不会再进来。