
🔥keyipatience:个人主页
🎬作者简介:C/C++后端开发学习者
🌟专栏传送门:《c++》《linux》《c++高阶数据结构》《c++数据结构与算法》《前端学习》
⭐️patience is key in life
Git 合并冲突
先看懂冲突是怎么制造出来的
核心前提:两个分支,在同一个文件的同一行,都做了修改并且各自提交了,Git 不知道该保留哪一个,就产生冲突。
整套复现流程
# 1. 创建并且直接切换到 dev1 分支(一步到位)
git checkout -b dev1
# 等价于 git branch dev1 && git checkout dev1
在 dev1 修改 ReadMe: 原来行 write aaa for new branch → 改成 write bbb for new branch
git add .
git commit -m "modify ReadMe"
# 2. 切回 master
git checkout master
这里 master 里还是老的 write aaa for new branch,然后在 master 上,同样这一行 ,改成 write ccc for new branch,再提交:
git add .
git commit -m "modify ReadMe"
现在历史分叉了:
- 共同祖先提交:内容是
aaa - dev1:改成
bbb,提交一次 - master:改成
ccc,提交一次 两条分支各自往前走,同一个位置改了不一样的内容,无法自动快进合并

执行合并,触发冲突
现在在 master,执行合并:
git merge dev1
输出关键提示:
Auto-merging ReadMe
CONFLICT (content): Merge conflict in ReadMe
Automatic merge failed; fix conflicts and then commit the result.
含义: Git 尝试自动合并,但是内容冲突,合并暂停了,进入「未合并状态」
查看状态:
git status
会看到:both modified: ReadMe 意思:这个文件,两边分支都修改了
两个选择写在提示里:
- 改完冲突,git add + git commit 完成合并
git merge --abort放弃这次合并,回到合并前干净状态
冲突标记怎么读
打开 ReadMe,Git 自动插入标记:
<<<<<<< HEAD
write ccc for new branch
=======
write bbb for new branch
>>>>>>> dev1
-
<<<<<<< HEAD<<<<<<<是标记开头; HEAD 就代表:你现在正在待着的分支 (本次是 master)。 这一段里面的文字,是 master 分支上写的内容:write ccc for new branch。 -
=======分割线,把两边分支的改动隔开,上面是当前分支,下面是要合并过来的分支。 -
>>>>>>> dev1>>>>>>>是标记结尾;dev1是另外那个分支的名字。 这一段里面的文字,是 dev1 分支提交的内容:write bbb for new branch。
这里 Git 不会替你决定保留 ccc 还是 bbb,必须人来手动决定 你可以:
- 保留 master 的 ccc
- 保留 dev1 的 bbb
- 自己写成新内容(比如
write bbb and ccc) 同时必须删掉 <<<<<<<=======>>>>>>> 这三行标记符号!
示例:我们选择保留 bbb,修改后文件:
hello bit
hello git
hello world
hello version1
hello version2
hello version3
write bbb for new branch
解决冲突之后,必须手动提交!(和快进合并最大区别)
改好文件,删除冲突标记:
git add .
git commit -m "merge ReadMe"
这次 commit 是专门的合并提交(merge commit) 原理图变化: master 指针往前走一步,生成一个新的提交节点,同时指向 master 原来的提交、dev1 的提交,两条分叉的线在这里交汇。

对比:
- Fast-forward 快进合并:没有新提交,不用手动 commit
- 冲突合并 / 分叉无冲突合并:产生 merge 合并提交,需要 commit
合并完成,dev1 的提交已经被并入 master,可以安全删除:
git branch -d dev1
Git 分支管理(Fast-forward /--no-ff)
快进合并(Fast-forward)的本质:master 没有新提交时,合并 dev 只是把 master 指针直接移动到 dev 的提交上,不会生成新的合并提交

核心问题:
- 合并完成、删除 dev 分支后,提交历史是一条完整直线
- 从
git log中看不出这段提交来自分支合并,无法区分是直接在 master 提交,还是从其他分支合入 - 分支开发的轨迹被抹除,不利于团队追溯问题、回滚版本
对比之前冲突场景的非快进合并: 两条分支各自有新提交,Git 自动生成双父合并提交 。哪怕删除 dev1 分支,git log --graph 依然能看到分叉、汇合的分支轨迹,完整保留合并信息。
--no-ff:强制禁用快进合并
--no-ff = no fast-forward,强制关闭快进模式。 哪怕当前合并完全满足快进条件,Git 也会强制生成一个新的合并提交,保证分支历史保留清晰的分叉、汇合痕迹。
命令格式
git merge --no-ff -m "合并说明文字" 分支名
输出提示:Merge made by the 'recursive' strategy.,代表不是快进合并
禁用快进后一定会生成新提交,因此可以用 -m 直接指定本次合并提交的备注。
执行 git log --graph --pretty=oneline --abbrev-commit,可以看到清晰的分叉图形:
* 5bd16b4 (HEAD -> master) merge with no-ff
|\
| * 41b882f (dev2) modify ReadMe
|/
即使后续删除 dev2 分支,这段分叉合并的历史也会永久保留。
通用分支管理策略
1.master 主分支
- 性质:绝对稳定
- 用途:仅用于发布正式版本,日常不直接在上面开发
- 所有合入 master 的代码,必须经过测试、可直接上线
2. dev 开发分支
- 性质:开发集成分支,持续迭代
- 用途:日常开发的主分支,所有功能开发最终都汇合到这里
- 版本开发完成、测试通过后,再从 dev 合并到 master 发布
3. 个人 / 功能分支(michael、bob 等)
- 团队成员开发新功能、修复 bug 时,都从 dev 拉出独立分支
- 开发完成、自测通过后,合并回 dev 分支
- 多人并行开发互不干扰,降低代码冲突概率
最终形成多层结构:master 最稳定,dev 是开发主线,下方挂载大量短期功能 / 个人分支,实现并行开发与版本稳定的平衡。
Git bug 分支 + git stash
想一想你正在 dev2 分支写代码,写到一半,代码还没提交(工作区有未保存的修改),这时 master 线上爆出紧急 bug,需要立刻修复。
难点:Git 切换分支时,工作区未提交的改动会跟着走,会污染要修复 bug 的 master 分支 ,不能直接切分支! 解决方案:
git stash储藏(暂存)当前正在写的代码现场。
stash 相关全套命令
git stash 储藏当前工作区 + 暂存区的改动(清空工作区、清空暂存区 ,回到干净的状态(回到上一次 commit 的样子),储藏之后 git status 查看,工作区变成干净状态,可以安心切换别的分支。
储藏的内容是临时的快照,不在正式 commit 历史里。
git stash list 查看所有储藏记录,格式 stash@{0}、stash@{1},数字越大代表越早储藏。
git stash pop 恢复最新的储藏(stash@{0}),恢复之后自动删掉这条 stash 记录
git stash apply 恢复储藏,但是不会删掉 stash 记录,储藏还在列表里
恢复指定储藏:git stash apply stash@{编号} 适合多次 stash、需要选择性恢复的场景。
完整流程
阶段 1:储藏当前dev2 的开发现场
git stash # 保存dev2写到一半的代码,工作区变干净
git status # 验证:working tree clean
如果没有stash直接切master:
阶段 2:切 master,创建临时 bug 分支 fix_bug,去修复线上 bug
git checkout master
git checkout -b fix_bug # 新建bug修复分支,基于master
# 修改文件,修复bug
git add ReadMe
git commit -m "fix bug"
阶段 3:bug 修好,合并回 master,删除临时 bug 分支
git checkout master
git merge --no-ff -m "merge fix_bug branch" fix_bug
git branch -d fix_bug # 删除用完的bug临时分支
用了 --no-ff,保留这次 bug 修复的合并记录
阶段 4:切回 dev2,把之前储藏的开发现场恢复回来,继续开发
git checkout dev2
git stash list # 看到之前存的 stash@{0}
git stash pop # 恢复代码,同时删除这条stash
# 继续写代码,写完正常提交
git add .
git commit -m "modify ReadMe"
这里一个非常关键的坑 : **fix_bug 修复的 bug 代码,只合并到 master,dev2 分支里是看不到这个 bug 修复代码的!**dev2 当初是从老版本 master 拉出来的;master 现在已经往前走了一个 bug 修复提交,dev2 的提交历史还停留在旧节点,两者分叉了。

怎么让 dev2 拿到 master 里已经修好的 bug 代码?
错误做法:直接切 master,合并 dev2。
风险:合并冲突会直接在 master(稳定上线分支) 上解决。 如果冲突很多、改错了,会直接把线上 master 主分支搞坏,非常危险!
git add .
git commit -m "merge master"
规范做法:
**先在自己的开发分支(dev2)里面合并 master,冲突在 dev2 本地解决、测试没问题;最后再切回 master 合并 dev2。**不会污染稳定的 master 分支。
当前在 dev2,执行合并 master
git merge master
很大概率出现冲突
打开文件,手动处理冲突标记 <<<<<<< HEAD / ======= / >>>>>>> master,改完保存
解决冲突之后,add + commit


