Git 如何解决合并冲突

冲突就是 Git 拒绝替你猜哪一边的修改该赢。修法是改一次文本,加两条命令。如果你还没动手就想撤,git merge --abort 会把仓库恢复到合并之前的状态。

🎙️ 发布并录制于: ·

先找出冲突文件,再动手改

先看 status,不要在整个项目里全局搜索替换。在 Unmerged paths 下面,Git 会把每个还需要你做决定的文件都列出来。如果这次合并是误操作,或者你现在没准备好处理,立刻 abort。abort 不是提交之后的补救命令,它是合并还在进行中时的干净出口。

git status
# Unmerged paths:
#   both modified:   config.py

# Leave the merge and return to the pre-merge state:
git merge --abort
真实报错:没有正在进行的合并可以中止fatal: There is no merge to abort (MERGE_HEAD missing).

运行 git status,读它开头那几行。你可能正在 rebase、cherry-pick 或者 revert,而不是在合并。用对应的那条命令,比如 git rebase --abort 或者 git cherry-pick --abort。如果 status 说工作区是干净的,那这次合并要么已经完成,要么根本没开始。

读懂标记,把文件改成正确的样子,然后收尾

打开一个冲突文件。等号那行上面是当前分支的内容,标签写着 HEAD。下面是要合进来的分支。你可以留一边、把两边拼起来,或者写出第三种结果。然后把三行标记全部删掉。目标不是让标记消失,而是让这个文件停在产品真正需要的状态上。

<<<<<<< HEAD
timeout = 30                 # current branch
=======
timeout = 60                 # incoming branch
>>>>>>> feature-x

# Edit to the intended result, with no markers:
timeout = 60

# Mark this file resolved, then finish:
git add config.py
git commit                   # save and close the pre-filled message
真实报错:还有文件没解决error: Committing is not possible because you have unmerged files.
fatal: Exiting because of an unresolved conflict.

运行 git status。凡是还在 Unmerged paths 下面的文件,先把内容改对,再运行 git add path/to/file。提交之前在项目里搜一遍连续七个小于号;漏掉的标记对 Git 来说是合法文本,对你的应用来说就是语法错误。最后一次提交之前,把相关的测试跑一遍。

用 ours 或 theirs 整份文件取一边

只有当某一整份文件确实该赢的时候,才用 ours 或 theirs。生成出来的 lock 文件适合这么处理,前提是团队紧接着就会重新生成它。但对包含两处有意修改的源码,这是个糟糕的捷径。普通合并时,ours 是你当前检出的那个分支,theirs 是被合进来的分支。

# Keep the whole file from the current branch:
git checkout --ours config.py
git add config.py

# Keep the whole file from the incoming branch:
git checkout --theirs config.py
git add config.py

# For a lock file, regenerate and test after choosing:
npm install
git add package-lock.json
rebase 会把这两个标签换个方向

rebase 用的是同一套标记,编辑加暂存的流程也一样,只是继续要用 git rebase --continue,退出要用 git rebase --abort。rebase 期间 ours 和 theirs 特别反直觉,因为 Git 是在把你的提交重放到另一个基点上。看标记上的标签,看内容本身,别只凭这两个词做决定。

减少重复冲突,并验证结果

冲突变难通常有三个原因:分支放得太久、一个提交里把格式调整和行为改动混在一起、两个人互不知情地在重做同一块设计。经常 pull,让分支活得短一点,把机械的格式化和逻辑改动分开提交。解决完之后看一眼暂存区的 diff。这能抓到最常见的那种错误:文件编译得过,但某一边真正需要的行为被悄悄丢掉了。

git diff --check             # catches leftover whitespace trouble
git diff --cached            # inspect exactly what the merge will commit
git status

# Habits that prevent giant conflicts:
git pull often
# keep branches short-lived (days, not months)
# do not mix whole-file formatting with logic changes
别把冲突标记提交上去

如果你的应用后来在一行以七个小于号开头的地方报语法错误,说明这次合并是在文本还没解决时就提交了。打开文件,决定正确的内容,删掉所有标记行,再跑一次测试或者解析器,把这次修复暂存并提交。盲选一边即使语法正确,也可能把一个 bug 修复删掉,所以除了标点,行为也要复查。

本页是我们 Git 系列中的一篇。想弄懂分支模型并听完整讲解,请读 10 分钟学会 Git →

Tell me what missed

A correction is more useful than a compliment. This goes straight to the person who writes SwiftGrasp.

Was this page useful?
0/1000

Please do not include passwords, private keys, or personal information.