Git + Gerrit 第四课:合并冲突解决

本节目标

这一节学习 Git 中非常重要、也非常常见的问题:冲突。

你要理解这些问题:

复制代码
什么是冲突?
为什么会产生冲突?
冲突文件里的 <<<<<<<、=======、>>>>>>> 是什么意思?
如何正确解决冲突?
解决冲突后为什么还要 git add?
Gerrit 工作流中遇到冲突应该怎么办?

本节重点命令:

复制代码
git status
git merge
git diff
git add
git commit
git merge --abort
git log --oneline --graph --all

1. 什么是 Git 冲突

冲突的本质是:

复制代码
两个分支修改了同一个文件的同一处内容,Git 无法自动判断应该保留哪一份。

例如:

main 分支把一行代码改成:

复制代码
title = main version

feature/login 分支把同一行代码改成:

复制代码
title = login version

当你把 feature/login 合并到 main 时,Git 不知道最终应该使用哪一行,于是就会产生冲突。

注意:

复制代码
冲突不是 Git 出错。
冲突是 Git 需要你这个开发者做判断。

2. 为什么会产生冲突

常见原因有这些:

  • 两个人修改了同一个文件的同一行

  • 两个分支都修改了同一个配置

  • 一个分支删除了文件,另一个分支修改了这个文件

  • 一个分支重命名文件,另一个分支继续修改旧文件

  • 长时间不更新主分支,导致自己的分支落后太多

最常见的是:

复制代码
你在功能分支开发时,主分支也被别人改了。
你们刚好改到了同一个位置。

3. 冲突示意图

一开始主分支是:

复制代码
A --- B --- C    main

你创建功能分支:

复制代码
A --- B --- C    main
           \
            D    feature/login

后来别人也修改了 main

复制代码
A --- B --- C --- E    main
           \
            D          feature/login

如果 DE 修改了同一个地方,合并时就可能冲突:

复制代码
git switch main
git merge feature/login

Git 会提示类似:

复制代码
CONFLICT (content): Merge conflict in readme.md
Automatic merge failed; fix conflicts and then commit the result.

意思是:

复制代码
readme.md 出现内容冲突。
自动合并失败。
请手动解决冲突,然后提交结果。

4. 冲突文件长什么样

假设 readme.md 出现冲突,文件内容可能变成:

复制代码
<<<<<<< HEAD
hello main
=======
hello feature
>>>>>>> feature/login

这几个标记非常重要。

含义如下:

复制代码
<<<<<<< HEAD
当前分支的内容
=======
被合并进来的分支内容
>>>>>>> feature/login

如果你当前在 main 分支执行:

复制代码
git merge feature/login

那么:

复制代码
HEAD

通常表示当前分支 main 的内容。

复制代码
feature/login

表示你正在合并进来的分支内容。

5. 解决冲突的核心原则

解决冲突不是简单删除某一边。

你需要判断:

复制代码
最终正确的代码应该是什么样。

例如冲突内容是:

复制代码
<<<<<<< HEAD
标题:主分支版本
=======
标题:登录功能版本
>>>>>>> feature/login

你可以选择保留当前分支:

复制代码
标题:主分支版本

也可以选择保留功能分支:

复制代码
标题:登录功能版本

也可以合并两边含义:

复制代码
标题:登录功能说明

关键是:

复制代码
最终文件里不能再保留冲突标记。

也就是说,解决后文件里不能还有:

复制代码
<<<<<<<
=======
>>>>>>>

6. 标准冲突解决流程

当你执行:

复制代码
git merge feature/login

遇到冲突后,标准处理流程是:

复制代码
git status

查看哪些文件冲突。

然后打开冲突文件,手动编辑成最终正确内容。

解决完成后:

复制代码
git add 冲突文件

最后提交:

复制代码
git commit

完整流程:

复制代码
git merge feature/login
git status

# 手动修改冲突文件

git add readme.md
git commit

注意:

复制代码
解决冲突后必须 git add。

因为 git add 的作用是告诉 Git:

复制代码
这个冲突文件我已经处理好了。

7. 为什么解决冲突后还要 git add

很多新手会疑惑:

复制代码
我已经手动改好文件了,为什么还要 git add?

因为 Git 不会自动知道你是否已经处理完冲突。

你执行:

复制代码
git add readme.md

是在告诉 Git:

复制代码
readme.md 的冲突已经解决,可以进入下一次提交。

如果还有冲突文件没有 git add,Git 不会让你完成合并提交。

8. 如何查看冲突状态

冲突发生后,先执行:

复制代码
git status

你可能看到:

复制代码
Unmerged paths:
  both modified: readme.md

意思是:

复制代码
readme.md 在两个分支都被修改了,现在处于未合并状态。

解决后执行:

复制代码
git add readme.md
git status

如果所有冲突都解决了,会看到类似:

复制代码
All conflicts fixed but you are still merging.

意思是:

复制代码
所有冲突已经解决,但合并流程还没有完成。

这时继续:

复制代码
git commit

完成合并。

9. 放弃本次合并

如果你合并后发现情况很复杂,暂时不想继续,可以放弃本次合并:

复制代码
git merge --abort

它的作用是:

复制代码
取消当前 merge,回到 merge 之前的状态。

适合这些场景:

  • 冲突太多,想重新整理思路

  • 合并错了分支

  • 发现自己当前分支不对

  • 想先备份或更新代码再重新合并

注意:

复制代码
git merge --abort 只用于正在合并且出现冲突的情况。

如果没有正在进行的 merge,它通常不能执行。

10. 实战练习:制造一个冲突

下面我们手动制造一个冲突,帮助你理解完整过程。

创建练习目录:

复制代码
mkdir git-conflict-demo
cd git-conflict-demo
git init

创建初始文件:

复制代码
echo "version: base" > config.txt
git add config.txt
git commit -m "添加基础配置"

创建功能分支:

复制代码
git switch -c feature/login

在功能分支修改同一行:

复制代码
echo "version: login feature" > config.txt
git add config.txt
git commit -m "修改登录功能配置"

切回主分支:

复制代码
git switch main

如果你的主分支叫 master,使用:

复制代码
git switch master

在主分支也修改同一行:

复制代码
echo "version: main update" > config.txt
git add config.txt
git commit -m "修改主分支配置"

现在合并功能分支:

复制代码
git merge feature/login

你应该会看到冲突提示。

11. 实战练习:解决冲突

查看状态:

复制代码
git status

打开 config.txt,你会看到类似:

复制代码
<<<<<<< HEAD
version: main update
=======
version: login feature
>>>>>>> feature/login

现在你决定最终内容为:

复制代码
version: main update with login feature

把整个文件改成:

复制代码
version: main update with login feature

然后执行:

复制代码
git add config.txt
git status
git commit

如果 Git 打开编辑器让你确认 merge commit message,保存并关闭即可。

如果你想直接写提交信息,也可以:

复制代码
git commit -m "合并登录功能配置"

查看提交图:

复制代码
git log --oneline --graph --all

你会看到合并历史。

12. 冲突解决时的三种选择

遇到冲突时,通常有三种处理方式。

12.1 保留当前分支内容

冲突内容:

复制代码
<<<<<<< HEAD
version: main update
=======
version: login feature
>>>>>>> feature/login

解决为:

复制代码
version: main update

适合:

复制代码
当前分支内容是正确的,被合并分支的修改不需要。

12.2 保留被合并分支内容

解决为:

复制代码
version: login feature

适合:

复制代码
功能分支内容是正确的,当前分支旧内容应该被替换。

12.3 手动合并两边内容

解决为:

复制代码
version: main update with login feature

适合:

复制代码
两边都有价值,需要人工整理成最终正确结果。

真实工作中最常见的是第三种。

13. 冲突解决完成后的检查

解决冲突后,不要急着提交。

建议检查:

复制代码
git status
git diff

如果已经 git add,可以看:

复制代码
git diff --cached

重点确认:

复制代码
冲突标记是否已经全部删除
最终代码逻辑是否正确
有没有误删别人代码
有没有把临时代码放进去

可以搜索冲突标记:

复制代码
git diff --check

它可以帮助发现一些空白符问题,但不能替代人工检查。

实际项目中,也可以在编辑器里搜索:

复制代码
<<<<<<<
=======
>>>>>>>

确保没有遗留冲突标记。

14. 常见冲突类型

14.1 内容冲突

最常见。

两个分支修改了同一行。

Git 提示:

复制代码
CONFLICT (content)

14.2 删除与修改冲突

一个分支删除了文件,另一个分支修改了文件。

Git 可能提示:

复制代码
CONFLICT (modify/delete)

你需要判断:

复制代码
这个文件最终应该保留还是删除。

如果保留:

复制代码
git add 文件名

如果删除:

复制代码
git rm 文件名

14.3 重命名冲突

一个分支重命名了文件,另一个分支也改了相关文件。

这种情况需要特别小心,因为可能涉及项目结构变化。

建议做法:

复制代码
先理解双方修改目的,再决定最终文件名和内容。

15. Gerrit 中的冲突

在 Gerrit 中,冲突通常发生在两种情况。

第一种:

复制代码
你本地更新目标分支时产生冲突。

例如:

复制代码
git fetch origin
git merge origin/master

或者:

复制代码
git pull

第二种:

复制代码
你的 Change 在 Gerrit 上显示无法自动合入。

这通常是因为目标分支已经有了新提交,而你的提交基于旧版本。

16. Gerrit 中处理冲突的一般思路

如果你的 Change 和目标分支冲突,一般流程是:

复制代码
git fetch origin
git switch feature/login
git merge origin/master

# 解决冲突

git add 冲突文件
git commit
git push origin HEAD:refs/for/master

有些团队更推荐使用 rebase:

复制代码
git fetch origin
git switch feature/login
git rebase origin/master

# 解决冲突

git add 冲突文件
git rebase --continue
git push origin HEAD:refs/for/master

rebase 后面会单独讲。

现在先记住:

复制代码
merge 是把目标分支合进你的分支。
rebase 是把你的提交重新放到目标分支最新位置之后。

具体团队用 merge 还是 rebase,要看项目规范。

17. Gerrit 中 amend 和冲突的关系

如果你的 Gerrit Change 已经存在,评审者让你修改,通常使用:

复制代码
git add .
git commit --amend
git push origin HEAD:refs/for/master

这样 Gerrit 会生成新的 Patch Set。

但如果你为了解决冲突引入了新的 merge commit,可能会让历史变复杂。

所以很多 Gerrit 团队更喜欢:

复制代码
rebase + amend

常见目标是:

复制代码
一个 Change 对应一个清晰的 commit。

不过新手阶段先不要急,先把冲突解决的基本流程掌握。

18. 冲突解决的工程习惯

解决冲突时,成熟工程师会这样做:

复制代码
先看 git status,确认哪些文件冲突
逐个文件解决,不要乱改无关内容
理解两边修改目的,而不是机械保留某一边
解决后搜索冲突标记
运行必要的编译或测试
最后再 git add 和 commit

不要这样做:

复制代码
看到冲突就全部保留自己的
看到冲突就全部保留别人的
不理解代码就随便删
冲突标记没删干净就提交
把无关格式化混进冲突解决

19. 常见错误

错误一:把冲突标记提交了

错误结果:

复制代码
<<<<<<< HEAD
some code
=======
other code
>>>>>>> branch

这种代码提交上去后,通常会导致编译失败。

提交前一定搜索:

复制代码
<<<<<<<
>>>>>>>

错误二:解决冲突后忘记 git add

如果忘记:

复制代码
git add 冲突文件

Git 会认为冲突还没有解决。

错误三:合并错分支

如果你发现合并错了,且还没完成合并:

复制代码
git merge --abort

错误四:不知道 HEAD 是谁

冲突中:

复制代码
<<<<<<< HEAD

表示当前分支内容。

所以合并前一定知道自己在哪个分支:

复制代码
git branch
git status

错误五:解决冲突时顺手重构

冲突解决应该尽量只处理冲突。

不要顺手做大量重构,否则评审者很难看懂:

复制代码
哪些是冲突解决
哪些是你新增的修改

20. 本节必须记住的命令

复制代码
git status
git merge 分支名
git merge --abort
git add 冲突文件
git commit
git diff
git diff --cached
git log --oneline --graph --all

对应含义:

复制代码
git status                         查看冲突状态
git merge 分支名                    合并指定分支
git merge --abort                  放弃当前合并
git add 冲突文件                    标记冲突已解决
git commit                         完成合并提交
git diff                           查看未暂存修改
git diff --cached                  查看已暂存修改
git log --oneline --graph --all    查看分支合并历史

21. 本节总结

这一节你学习了 Git 冲突解决:

  • 冲突是两个分支改到同一处,Git 无法自动判断

  • 冲突文件中 HEAD 表示当前分支

  • ======= 上下分别是两个版本的内容

  • 解决冲突要编辑成最终正确内容

  • 解决后必须执行 git add

  • 如果不想继续合并,可以用 git merge --abort

  • Gerrit 中冲突通常意味着你的 Change 落后目标分支

  • 不要机械保留某一边,要理解代码含义

冲突解决是开发工程师的基本功。

真正重要的不是命令,而是判断:

复制代码
最终代码应该是什么样。

下一节建议学习:

复制代码
Git rebase:为什么 Gerrit 中经常使用 rebase,以及 rebase 和 merge 的区别。
相关推荐
HZZSDSCYZ8 小时前
2026年杭州电商新趋势:专业公司如何引领未来市场
大数据·人工智能·python
搞科研的小刘选手9 小时前
【经管方向EI会议】第七届经济管理与大数据应用国际学术会议(ICEMBDA2026)
大数据·区块链·可视化·管理·供应链·经济·消费者行为
久菜盒子工作室9 小时前
港股创新药趋势走坏了吗
大数据·人工智能
出海小龙9 小时前
联盟营销实战技能体系:从市场研究到数据优化的完整盈利框架
大数据·前端·人工智能
无忧智库9 小时前
某能源集团多Agent协同的电力交易策略优化与实时调度决策系统建设方案(WORD)
大数据·人工智能·自动化
geneculture10 小时前
从“巴别塔”到“耶路撒冷”:融智学应对AI时代治理困境的系统方案
大数据·人工智能·融智学的重要应用·哲学与科学统一性·融智时代(杂志)·人际间性·人机间性
暴躁小师兄数据学院10 小时前
【AI大模型应用开发工程师特训笔记】第04讲(第五章):条件判断与流程控制
大数据·人工智能·python·学习
计算机安禾10 小时前
【算法分析与设计】第20篇:图论中的NP困难问题与近似策略
大数据·人工智能·算法
云边云科技_云网融合10 小时前
企业级网络智能运维体系构建:从被动响应到主动预判
大数据·网络·人工智能