分支合并与冲突解决
本教程共 26 篇 · 第 10 篇 · 更新于 2026-07-29 · 约 8 分钟阅读
10. 分支合并与冲突解决
本节目标:理解 git merge 的快进和三方合并两种模式,学会识别并手动解决代码冲突,让分支修得掉也合得拢。
分支存在的意义,最终都要回到合并上。写好的功能、修完的 bug,不合并回主线就只是自嗨。Git 的 merge 就是把两条分叉的时间线重新拧成一股。
merge 的基本用法
合并前,先确认你在”要合并到哪个分支”上。想把 feature 合进 main,就先切到 main。
git switch main # 旧写法:git checkout main
git merge feature
一句话解释:把 feature 分支的修改并入当前分支(main)。
快进合并(Fast-forward)
最简单的合并场景:目标分支没有新提交。
你在 main 上创建了 feature,然后只在 feature 上提交了两次。这期间 main 原地没动。Git 要做的只是把 main 指针往前挪到 feature 的位置。
git merge feature
Updating a1b2c3d..f4e5d6c
Fast-forward
feature.py | 10 ++++++++++
1 file changed, 10 insertions(+)
输出里那个 Fast-forward 就是关键信号。这种合并没有额外提交,也没有冲突风险,干净利落。
三方合并(Three-way merge)
现实没这么一帆风顺。如果 main 在你开发期间也往前走了一步,两条线就分叉了。Git 没法再简单地挪指针,只能做”三方合并”。
它取出三个快照:两条分支各自的最新提交、以及它们的共同祖先。三者一比对,生成一个全新的”合并提交”。
git merge feature
Merge made by the 'recursive' strategy.
readme.md | 2 ++
1 file changed, 2 insertions(+)
这个合并提交有两个父提交,所以提交历史会出现一个倒 V 字形。用 --graph 看就很直观。
git log --oneline --graph
* abc1234 (HEAD -> main) Merge branch 'feature'
|\
| * def5678 (feature) 添加新功能
* | 9f0g1h2 修复主线的一个错别字
|/
* a1b2c3d 共同祖先
当冲突发生时
如果你和同事改了同一个文件的同一行,Git 就懵了。它做不了决定,把球踢回给你。
git merge feature
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Git 没有创建合并提交,整个合并流程暂停。你的工作目录里,冲突文件会被塞进一堆标记。打开冲突文件,能看到这样的结构:
<<<<<<< HEAD
<button class="btn-primary">确认</button>
=======
<button class="btn-submit">确定</button>
>>>>>>> feature
<<<<<<< HEAD到=======之间:你在当前分支上的版本。=======到>>>>>>> feature之间:要合并进来的分支版本。
你的任务就是决定:要哪边?还是两边都留?还是重写?
解决冲突的四个步骤
假设最终你决定用”确认”这个文案,同时保留对方的样式类。
- 编辑文件,删掉所有冲突标记,留下你想要的内容。
<button class="btn-submit">确认</button>
- 把解决后的文件标记为已解决。
git add index.html
- 检查是否还有其它冲突文件。
git status
- 提交合并结果。
git commit
Git 会自动生成类似 “Merge branch ‘feature’” 的提交信息,直接保存即可。
想反悔怎么办
解决到一半发现搞砸了,可以用 git merge --abort 一键回到合并前的状态。
git merge --abort
abort 在合并冲突、工作目录脏乱但有暂存内容时都能救场。但要记住,工作目录里未提交的改动可能会丢,所以合并前尽量保持干净状态。
除了 --abort,也可以用 git reset --hard HEAD 回到合并前最后一次提交。更暴力,也更彻底,所有未提交的改动都消失。用前三思。
有时候空白在捣鬼
合并报错,打开文件一看其实逻辑上没冲突,纯粹是缩进或换行符在搞事。Git 提供了两个参数来忽略这类差异:
git merge -Xignore-all-space feature # 完全忽略空白
git merge -Xignore-space-change feature # 把多个空白当作等价
只想选一边
某些场景下,你明确知道要哪个版本。-Xours 和 -Xtheirs 能直接站队。
git merge -Xours feature # 所有冲突自动选当前分支版本
git merge -Xtheirs feature # 所有冲突自动选要合并分支的版本
注意:非冲突部分还是正常合并。这两个选项只影响冲突部分。
图形化工具来帮忙
如果你看标记眼花了,git mergetool 可以启动可视化工具。
git mergetool
Git 会按顺序弹出每个冲突文件的三方对比界面。改完保存,Git 自动把文件标记为已解决。
本章小卡片
| 场景 | 命令 |
|---|---|
| 合并分支 | git merge <branch> |
| 中断合并 | git merge --abort |
| 忽略空白合并 | git merge -Xignore-space-change <branch> |
| 冲突时选当前分支 | git merge -Xours <branch> |
| 冲突时选对方分支 | git merge -Xtheirs <branch> |
| 启动合并工具 | git mergetool |
Note合并前先
git status确认工作目录干净。有未提交的改动就合并,大概率会被拒绝或者把历史搅浑。