Git中的恶意合并 - 它们从哪里来?

4

我已经阅读了这个问题和答案,但对我来说不清楚的是谁创建了“在任何父级中都没有出现的更改”。

是git合并算法搞砸了吗?

还是因为用户必须手动调整冲突以使其构建,引入了在任何一个父级中都不存在的新代码?


我已经添加了一种具体的方法来展示恶意合并:git log -c 显示带有 '++' 的行。请参见我下面编辑过的答案。 - VonC
我曾经将 git://devil@github.com/hell.git 添加为远程仓库并拉取了代码... 在此过程中遇到了许多恶意合并。我不建议这样做。 - ereOn
3个回答

4

这在正确的答案的第一条评论中有解释。你合并时没有进行提交(通过冲突或--no-commit),然后在提交之前添加了额外的更改。

注意,解决合并冲突并不是邪恶的,你只需选择存在于一个或两个冲突方的代码即可。如果你添加了某些不存在于任何一方的代码,现在就变成了邪恶的合并。


有时候,解决冲突的唯一方法就是添加代码,这些代码在任何一个父分支中都不存在。当然,虽然这种合并解决方案可能是邪恶的,但我认为它更像是“法律上的邪恶”,而不是“混乱邪恶”的合并,后者会添加与合并内容无关的代码。 - Cascabel
@Jefromi,这正是我问题所在的地方。我不知道如何协调“不要破坏构建”和避免恶意合并。 - Benjol
@Benjol:有时候你只需要从一个父级中选择一行而不是另一个类似的行-但你是对的,在现实世界中大多数情况下,你需要做更多的事情。 - Cascabel

3

那个评论是一个有趣的例子,说明了"恶意"合并是如何发生的:

有时候最小的手动解决方案会导致出现之前不存在的代码行。
例如:

  • 'ours' 改变了函数名称,
  • 'theirs' 改变了返回值,
  • 我们需要一个新名称和新返回值的方法。

这算是一个恶意合并吗?也就是说,恶意合并有时是必要的吗?

请注意,这篇文章在另一个上下文中提到了"恶意合并"(不期望的合并),并主张始终使用变基(rebase)而不是合并...但这会忽略"git pull --rebase"的危险


Junio C Hamano,git的主要维护者,在他的2013年4月博客文章中精确地指出:
“邪恶合并”在现实生活中发生的一个典型例子(并且是一件好事)是为了调整语义冲突。它几乎从来没有与文本冲突有任何关系。
(通常是API更改,例如:您添加了一个参数,而另一个开发人员调用该函数...但是没有任何额外的参数)
这意味着您必须在合并时解决语义冲突(例如缺少一个现在需要一个参数的函数的参数),这意味着创建一条线路:
  • 不存在于您的代码中(其中您正确地进行了API更改)
  • 不存在于您现在正在合并的远程分支中(其中其他开发人员不知道API更改)

这使得合并成为了"恶意合并"

使用"git log -c/--cc",这样一行将会以双加号的形式出现在多向补丁输出中,以显示"它在父提交中不存在"。

来自git log手册页面

差异格式化

-c::

使用此选项,合并提交的差异输出会同时显示从每个父提交到合并结果的差异,而不是一次显示一个父提交和结果之间的差异对。
此外,它仅列出了从所有父提交修改过的文件。

0

当开发人员遇到合并冲突时,他必须手动解决,而在这样做的过程中,他会更改与合并冲突本身无关的代码。Git的合并算法不会自行插入不相关的“恶意”代码更改。


挑剔一点的话,你可以添加与合并冲突相关但不是来自任何一个父版本的代码,这样你就会得到一个至少有点邪恶的合并。 - Cascabel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接