“CONFLICT (content): Merge conflict in …” 是协作里最常见的 git 报错之一。这篇在本机把 merge、rebase、stash pop、cherry-pick 的冲突都复现一遍,看每一种的提示、冲突标记里谁是谁、状态码含义,以及 -X ours 和 rerere 这类“省事”选项到底做了什么。
$ git merge feature (退出码 1)
Auto-merging f.txt
CONFLICT (content): Merge conflict in f.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git status --short; git status | sed -n 1,8p
UU f.txt
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: f.txt
$ cat f.txt
title
line A
<<<<<<< HEAD
line B (main)
=======
line B (feature)
>>>>>>> feature
line C
$ printf "title\nline A\nline B (both)\nline C\n" > f.txt && git add f.txt && git commit -qm "merge feature" && git log --oneline --graph
* c732520 merge feature
|\
| * 0fd0e30 feature: edit B
* | 901bfb9 main: edit B
|/
* a77f801 base
$ git merge feature >/dev/null 2>&1; git merge --abort && git status | head -2 && cat f.txt
On branch main
nothing to commit, working tree clean
title
line A
line B (main)
line CHEAD 一侧是当前分支,另一侧是被合并的分支;解决后 add 并 commit,或者 merge --abort 放弃。
$ git switch -q feature && git rebase main (退出码 1)
Auto-merging f.txt
CONFLICT (content): Merge conflict in f.txt
Rebasing (1/1)
error: could not apply 0fd0e30... feature: edit B
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Could not apply 0fd0e30... # feature: edit B
$ cat f.txt
title
line A
<<<<<<< HEAD
line B (main)
=======
line B (feature)
>>>>>>> 0fd0e30 (feature: edit B)
line C
$ git status | sed -n 1,9p
interactive rebase in progress; onto 901bfb9
Last command done (1 command done):
pick 0fd0e30 # feature: edit B
No commands remaining.
You are currently rebasing branch 'feature' on '901bfb9'.
(fix conflicts and then run "git rebase --continue")
(use "git rebase --skip" to skip this patch)
(use "git rebase --abort" to check out the original branch)
$ git checkout --ours f.txt && cat f.txt && git checkout --theirs f.txt && cat f.txt
title
line A
line B (main)
line C
title
line A
line B (feature)
line C
Updated 1 path from the index
Updated 1 path from the index
$ git checkout -m f.txt >/dev/null 2>&1; git rebase --abort && git status | head -1
On branch feature
$ git switch -q feature; git merge main >/dev/null 2>&1; echo "—— 同样站在 feature 上,git merge main 的 --ours / --theirs:"; git checkout --ours f.txt && grep "line B" f.txt && git checkout --theirs f.txt && grep "line B" f.txt
—— 同样站在 feature 上,git merge main 的 --ours / --theirs:
line B (feature)
line B (main)
Updated 1 path from the index
Updated 1 path from the index
$ git merge --abort; git rebase main >/dev/null 2>&1; echo "—— 同样站在 feature 上,git rebase main 的 --ours / --theirs:"; git checkout --ours f.txt && grep "line B" f.txt && git checkout --theirs f.txt && grep "line B" f.txt; git rebase --abort
—— 同样站在 feature 上,git rebase main 的 --ours / --theirs:
line B (main)
line B (feature)
Updated 1 path from the index
Updated 1 path from the index收尾命令是 rebase --continue / --skip / --abort;ours 与 theirs 的含义和 merge 相反。
$ echo "line B (local work)" > f.txt && sed -i.bak "s/line B (local work)/line A\nline B (local)/" f.txt; rm f.txt.bak; git stash -q; git switch -q feature; git stash list
stash@{0}: WIP on main: 901bfb9 main: edit B
$ git stash pop (退出码 1)
Auto-merging f.txt
CONFLICT (content): Merge conflict in f.txt
On branch feature
Unmerged paths:
(use "git restore --staged <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: f.txt
no changes added to commit (use "git add" and/or "git commit -a")
The stash entry is kept in case you need it again.
$ git stash list; git status --short
stash@{0}: WIP on main: 901bfb9 main: edit B
UU f.txt
$ git checkout -q HEAD -- f.txt && git stash drop && git stash list | wc -l | tr -d " "
Dropped refs/stash@{0} (c3bfa5099c38111eb6d6cb64818590b16c2405e4)
0冲突时 stash 条目保留,解决后要自己 drop。
两边改同一行:
Auto-merging f.txt
CONFLICT (content): Merge conflict in f.txt
Automatic merge failed; fix conflicts and then commit the result.
UU f.txt
两边都新增同名文件:
Auto-merging new.txt
CONFLICT (add/add): Merge conflict in new.txt
Automatic merge failed; fix conflicts and then commit the result.
AA new.txt
一边改、一边删:
CONFLICT (modify/delete): f.txt deleted in feature and modified in HEAD. Version HEAD of f.txt left in tree.
Automatic merge failed; fix conflicts and then commit the result.
UD f.txt
二进制文件两边都改:
warning: Cannot merge binary files: bin.dat (HEAD vs. feature)
Auto-merging bin.dat
CONFLICT (content): Merge conflict in bin.dat
Automatic merge failed; fix conflicts and then commit the result.
UU bin.dat
cherry-pick 同一行:
Auto-merging f.txt
CONFLICT (content): Merge conflict in f.txt
error: could not apply 8397524... feat
UU f.txtcontent、add/add、modify/delete、二进制各有不同的提示和状态码。
$ git -c merge.conflictStyle=zdiff3 merge feature >/dev/null 2>&1; cat f.txt; git merge --abort
title
line A
<<<<<<< HEAD
line B (main)
||||||| a77f801
line B
=======
line B (feature)
>>>>>>> feature
line C
$ git merge -X ours feature 2>&1 | head -3; grep "line B" f.txt; git log --oneline -3
Auto-merging f.txt
Merge made by the 'ort' strategy.
line B (main)
fd3ee28 Merge branch 'feature'
901bfb9 main: edit B
0fd0e30 feature: edit B
$ git config rerere.enabled true; git merge feature 2>&1 | head -4; printf "title\nline A\nline B (both)\nline C\n" > f.txt && git add f.txt && git commit -qm "merge feature"
Auto-merging f.txt
CONFLICT (content): Merge conflict in f.txt
Recorded preimage for 'f.txt'
Automatic merge failed; fix conflicts and then commit the result.
Recorded resolution for 'f.txt'.
$ git reset -q --hard HEAD~1; git merge feature 2>&1 | head -4; cat f.txt; git status --short
Auto-merging f.txt
CONFLICT (content): Merge conflict in f.txt
Resolved 'f.txt' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
title
line A
line B (both)
line C
UU f.txtzdiff3 让冲突块多一段共同祖先;-X ours 会丢另一边的改动;rerere 记住解决办法。