Skip to main content

git 智能的认为你“反悔”了

wKevin

摘要:

假设一个文件中包含下面几句:

if __name__ == "__main__":
print("Hello")
exit

如果在 git master 分支中修改了一句:

    print("Hello world")

另外一个分支 b1 先做了相同的修改,做了 git 提交,然后后删除了 world 回到原始状态,又做了 git 提交。

此时 merge 两个分支:

alt text

结果中 world 有?还是没有?

  • 支持“没有”的

认为 b1 分支中第二次 commit 时间更靠后,应该更应该被采纳,删除了 world 肯定是因为发现了“错误”,都在 b1 中修正了这个“错误”了,为什么 master 分支中还要保留这个“错误”呢?

万一这不是个错误,而是个“病毒”,b1 中及时删除了这个病毒,难道合入 master 后还要保留这个病毒?

  • 支持“有”的

认为 master 分支中的增加 world 操作是对原文的修改,b1 分支中先加后删是“反悔”了,在做回退(rollback)操作,那么 master 分支中的操作更有价值,更应该保留。

万一 master 分支这个操作修复了病毒,而 b1 分支上没意识到呢?

  • 支持“冲突提示”的

双方都修改了同一行,为啥不提示冲突?人工解决不是更稳妥么?

结果:

“有” -- 即:git 认为 b1 中是回退操作,master 上的修改更有价值,被采纳。

git merge 操作的基本流程是:

  • 寻找 3 个点:我们暂时称为:A、B、C 点
    • A: master 分支最新提交
    • B: b1 分支最新提交
    • C: master 和 b1 的 git merge base,例子中即 create(78e4ce95)
  • 先用 A 与 C 对比,因为 A-C 之间可能有若干次提交,中间的就跳过不管了,只对比 A-C 两次提交的差异
  • 再用 B 与 C 对比,与上面相同
  • 然后用 2 次对比结果再进行对比

所以,寄希望 A-C 或 B-C 之间的变化能被 git 发现,可能会失望了。所谓“智能”的发现了回退、反悔,应该只能看做对 git 这个工作流程的溢美之词。

总结:

不要以为 merge 成功了,没有提示冲突,就以为代码合并的没有问题,现实情况是复杂的,git 并没有你想象的那么智能,也许以后 git + LLM 说不定可以解决这个问题。

这个问题非常隐蔽,如果 b1 分支上不是完全回退,而是稍微有一点点变化,都会造成一次冲突,人工介入时就能化解危机。

也许将来 git 会给出解决方案,在此之前,某个分支中解决的问题最好及时在存在同类问题的其他分支上做修正

参考: