为什么Git合并冲突时会改变行顺序?Git合并冲突计算逻辑是怎样的?
合并冲突原因及Git合并逻辑说明
为什么会出现本次冲突
Git默认使用基于行的三路合并算法,判断是否冲突的核心依据是「两个分支相对于共同祖先的改动是否作用在同一个上下文行块」,而非语义上的“修改位置在头部/尾部”。
你遇到的冲突本质是Git在匹配行的上下文时,无法确定b及前后空行的对应关系:
- 共同祖先(merge base)版本的
base.md结构:
1: 2: 3: b
base分支(ours)改动:在文件头部新增了一行a,末尾新增了一行空行,最终结构:
1: a 2: 3: b 4:
feat分支(theirs)改动:在文件尾部新增空行和c,最终结构:
1: 2: 3: b 4: 5: c
Git在做行匹配时,发现b前面的空行块在两个分支都出现了变化:ours版本里b前面是a + 1个空行,theirs版本里b前面是2个空行,两个分支都修改了b所在的相邻上下文块,因此判定为冲突,不会自动把c追加到末尾。
你观察到的行号不一致是正常现象:冲突块里的行号是合并生成的临时文件的行号,而非原分支文件的行号,不代表原分支里b的实际位置。
Git合并冲突的计算逻辑
Git合并(默认递归策略)的核心步骤如下:
- 找到两个待合并分支的最近共同祖先提交,作为合并的基准版本
- 生成两份diff:基准版本 vs 当前分支(ours)的改动、基准版本 vs 待合入分支(theirs)的改动
- 逐段匹配两份diff的改动范围:
- 若某段行仅其中一方有改动,自动采纳改动后的内容,无冲突
- 若某段行双方都做了不一致的改动,标记为冲突,生成冲突块标注三方内容(开启diff3时会显示基准版本的内容)
注:Git的行匹配逻辑会优先匹配连续的公共行块,不会预判代码语义,因此会出现语义上不冲突但Git判定冲突的情况,本次就是典型的上下文空行匹配异常导致的误判冲突。
内容的提问来源于stack exchange,提问作者tianzhich
相关产品推荐
相关产品推荐

