Git 分支合并(merge)的核心逻辑是 "整合两个分支的提交历史",你觉得"相互合并",本质是 Git 会把两个分支从"共同祖先提交"之后的所有修改都整合到一起,最终形成一个统一的提交历史------并非"分支A合并到B,B的修改就不影响A",而是双向整合(但分支本身不会自动切换,需手动操作)。
要理解这个问题,关键要搞懂 Git 合并的底层逻辑和"分支的本质":
一、先明确:Git 分支的本质是"提交指针"
Git 里的分支,并不是一个独立的文件夹或副本,而是一个 指向某个提交(Commit)的指针 。
比如:
main分支指针指向它的最新提交(如C3);- 你从
main拉的feature分支指针,初始也指向C3(共同祖先); - 之后你在
feature改代码提交C4、C5,feature指针就移动到C5;同时别人在main改代码提交C6,main指针移动到C6。
此时两个分支的提交历史是:
C0 → C1 → C2 → C3(共同祖先)→ C4 → C5(feature)
C0 → C1 → C2 → C3(共同祖先)→ C6(main)
二、merge 的核心逻辑:"整合分歧,而非单向覆盖"
当你执行 merge 时(比如"把 feature 合并到 main"),Git 做的不是"用 feature 覆盖 main",而是:
- 找到两个分支的 共同祖先提交 (上例中的
C3); - 对比:
main从C3到C6的所有修改(A组修改);feature从C3到C5的所有修改(B组修改); - 把 A 组和 B 组修改 同时整合 到一起,生成一个新的"合并提交"(如
C7); - 最后,只有当前所在的分支指针会移动到合并提交
C7(另一个分支指针不变)。
整个过程的结果:
main分支的历史变成:C0→C1→C2→C3→C6→C7(包含了feature的C4、C5所有修改);feature分支的历史仍然是:C0→C1→C2→C3→C4→C5(指针没动,还是指向C5)。
你觉得"相互合并",其实是 main 整合了 feature 的修改,而 feature 并没有自动整合 main 的修改------除非你再切换到 feature 分支,执行 git merge main,把 main 的 C6、C7 修改整合到 feature 里。
三、为什么会有"双向影响"的错觉?
-
合并是"当前分支吸收目标分支的修改"
比如:
- 切换到
main,执行git merge feature→main吸收feature的修改(main有了feature的代码); - 切换到
feature,执行git merge main→feature吸收main的修改(feature有了main的代码);
如果你先后做了这两步,就会感觉"两个分支互相合并了"------但这是两次独立的合并操作,不是 Git 自动"双向合并"。
- 切换到
-
共同祖先的存在,让"双向修改"被统一整合
两个分支的修改都基于共同祖先,Git 会把双方的修改都保留(除非有冲突,需要手动解决)。比如:
main改了a.txt的第1行;feature改了a.txt的第5行;
合并后,a.txt会同时保留"第1行的修改"和"第5行的修改"------这不是"相互覆盖",而是"双向整合",本质是 Git 要保留所有分支的有效修改。
四、关键澄清:merge 不会"自动让两个分支同步"
很多人误以为"合并后两个分支就一样了",但实际是:
- 只有 当前执行 merge 的分支 会被更新(指针移到合并提交);
- 目标分支(被合并的分支)的指针仍然停留在原来的最新提交,不会自动同步当前分支的修改。
比如:
- 切换到
main,git merge feature→main有了feature的修改(main指针到C7); - 此时
feature指针还是C5,feature分支里没有main之前的C6修改; - 只有当你切换到
feature,再执行git merge main,feature才会吸收main的C6和C7修改,此时两个分支的提交历史才完全一致。
五、举个具体例子,一看就懂
假设初始状态(共同祖先 C3):
main: C0 → C1 → C2 → C3 → C6
feature: C0 → C1 → C2 → C3 → C4 → C5
第一步:main 合并 feature
bash
git checkout main
git merge feature
Git 整合 C4、C5(feature 的修改)和 C6(main 的修改),生成合并提交 C7:
main: C0 → C1 → C2 → C3 → C6 → C7(包含 C4、C5 的修改)
feature: C0 → C1 → C2 → C3 → C4 → C5(无变化)
第二步:feature 合并 main
bash
git checkout feature
git merge main
Git 整合 C6、C7(main 的修改)到 feature,生成合并提交 C8:
main: C0 → C1 → C2 → C3 → C6 → C7
feature: C0 → C1 → C2 → C3 → C4 → C5 → C8(包含 C6、C7 的修改)
此时两个分支的代码完全一致,这就是你感知到的"相互合并"------但这是两次手动操作的结果,不是 Git 自动双向合并。
总结
Git merge 的"相互合并"本质是:
- 合并的核心是 整合两个分支的分歧修改(从共同祖先之后的所有修改),而非单向覆盖;
- 只有"当前分支"会吸收目标分支的修改,目标分支不会自动同步;
- 若想让两个分支完全一致,需要在两个分支上分别执行 merge(或用
rebase同步历史)。
简单说:merge 是"当前分支拿目标分支的修改",不是"两个分支互相推送修改"------你看到的"相互合并",是两次合并操作的结果,而非 Git 的默认行为。