外观
09 · 冲突处理
冲突不是仓库坏了,是 Git 拒绝猜测「同一处两边都改了该留谁」。处理原则:用 abort 撤退,用 add 标记已解决,不要在中途 reset --hard。
什么时候会停下来
merge、pull(merge 模式)、rebase、cherry-pick、stash apply/pop 都可能冲突。git status 会明确写:
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)或 rebase / cherry-pick 对应的 --continue / --abort。
先看卡在哪种操作里:
bash
git status
# 也可看这些文件是否存在:
# .git/MERGE_HEAD → merge
# .git/REBASE_HEAD → rebase
# .git/CHERRY_PICK_HEAD → cherry-pick冲突标记怎么读
<<<<<<< HEAD
当前分支上的内容
=======
进来的那边的内容
>>>>>>> feature/login<<<<<<<到=======:当前 HEAD 一侧。=======到>>>>>>>:被合入 / 被 replay 的一侧。
你的任务是编辑成最终该留下的内容(可以是一边、也可以是两边拼起来),删掉这三行标记。
有的文件是二进制,没有标记,只能选一边或用外部工具。
标准处理步骤
bash
git status # 列出未合并路径
# 编辑每个冲突文件,去掉标记
git add src/login.ts # 标记该文件已解决
git status # 全部 resolved 后再继续
# 三选一,看你在哪种操作里:
git commit # merge:有的 Git 版本可用 merge --continue
git merge --continue
git rebase --continue
git cherry-pick --continue--continue 时若 Git 说「没有要提交的」,可能这颗补丁已经完全被另一边包含,rebase 下用 git rebase --skip。
放弃这次操作
bash
git merge --abort
git rebase --abort
git cherry-pick --abort工作区回到该操作开始前。这是后悔时的第一选择。
不要在有 unmerged paths 时:
bash
git reset --hard # 会丢掉已手工解决的部分,状态也更难读除非你已决定完全放弃,并且能接受回到操作前的 HEAD(效果类似 abort,但 abort 更明确)。
ours / theirs:merge 和 rebase 相反
可以用命令整文件取一边(仍然要 add):
bash
git checkout --ours src/login.ts
git checkout --theirs src/login.ts
# 新写法(Git 2.23+):
git restore --ours --worktree --staged src/login.ts
git restore --theirs --worktree --staged src/login.ts含义:
| 操作 | --ours | --theirs |
|---|---|---|
merge(当前在 main,merge feature) | main(你原来的) | feature(进来的) |
rebase(当前在 feature,rebase 到 main) | 上游 / 新基(main) | 正在 replay 的那颗提交(你的补丁) |
rebase 时很多人按 merge 的直觉取 ours,结果把自己的功能整文件丢掉了。不确定就打开文件看标记,不要整文件 checkout。
stash apply 冲突时,ours 是当前工作区所在分支,theirs 是 stash。
只看冲突文件
bash
git diff # 未解决时会以合并差异格式显示
git diff --name-only --diff-filter=U解决完却无法 continue
常见原因:
- 还留着
<<<<<<<就add了。git grep '<<<<<<<'搜出来改掉。 - 解决后忘了
git add。 - 编辑器又把文件改回冲突状态。
- rebase 停在空提交:
git rebase --skip。
反复出现相同冲突
bash
git config --global rerere.enabled trueGit 会记住「这类冲突你怎么解的」,下次自动复用。见 01 章。
合并合完了才发现错了
已经不在 unmerged 状态:
- 未 push:
git reset --hard ORIG_HEAD(确认没有其它未提交宝贝)。 - 已 push 的 merge:
git revert -m 1 <merge_sha>。
不要为了「清冲突」重 clone。冲突文件都在工作区,abort 就能干净。
上一章:08 · stash / worktree · 下一章:10 · 标签与发布