合并提交所做的更改无法通过 `git bisect` 或 `git log -S --all` 命令找到。

14
我对一个文件进行了修复并提交到了我的git代码库中。之后的一段时间,我发现这个问题又出现了。我想知道哪次提交将修复内容删除了,所以我尝试使用了git bisect和git log --all -S TERM(其中"TERM"是我修复时添加的字符串,在整个项目中都没有出现过)。结果发现git bisect找错了提交,而git log --all -S TERM只列出了我添加TERM的提交,并没有列出删除它的任何提交,尽管在master分支中它已经不再存在了。在手动查找一番之后,我发现在两个分支之间进行了一次合并提交。一个分支有我的修复,而另一个分支没有。合并的作者选择了没有我的修复的分支(奇怪的是,在这个文件中没有冲突),我的问题如下:
1.git bisect为什么无法找到合并更改?我在manpage中没有看到有关此限制的任何信息。有没有一种不同的使用方式,可以找到上述情况下的坏合并?
2.git log --all -S TERM为什么没有列出合并提交?manpage说它会列出“引入或删除实例”的提交。那个合并提交没有删除我的字符串吗?有没有一种不同的使用方式,可以找到上述情况下的坏合并?
3.如果git bisect和git log -S在上述情况下无用,那么找到坏的合并的有效方法是什么?没有这些工具,跟踪问题花费了我相当长的时间。

1
git bisect可以找到合并提交,但是如果在你正在二分的范围内有一个更早的提交(例如远端的祖先)有文件的“破损”版本,那么显然会优先选择它。 - CB Bailey
是的,这可能就是我遇到的情况。在这种情况下,有没有任何变通方法可以让 bisect 找到真正的罪犯? - Rich
这是一个很好的问题,你真的需要将二分范围限制在那些具有你的修复程序作为祖先的提交中... 不确定。 - CB Bailey
你真的需要从rev-listbisect中结合使用--ancestry-path。虽然我不确定你是否可以同时使用两者,但如果可以的话,应该能够找到抹去你更改的第一个合并。 - CB Bailey
git reflog和git reflog --all将给出误放提交的提交哈希值。尝试使用它来查找。 - StaticVariable
2个回答

5
为什么 git log --all -S TERM 命令没有列出合并提交?您需要添加 -m 选项:
git log -m --all -S TERM

为了理解为什么在这种情况下需要一个特殊选项,让我们首先看一下git log -p的操作,它必须包括列出历史记录中的更改。您可以轻松检查,默认情况下不会显示合并提交的更改。原因是一个更改是“两个版本之间的差异”,而对于合并提交,我们有三个(或更多)版本。 -m选项解决了这个问题:

差异格式

...

-m

此标志使合并提交显示与常规提交相同的完整差异; 为每个合并父级生成单独的日志条目和差异。--first-parent选项给出时,只显示与第一个父级的差异; 在这种情况下,输出表示合并带入当前分支的更改。

然后,假设git log -S的工作方式就像通过处理git log -p返回的差异一样,您应该承认默认情况下合并提交将被排除在结果之外。但是,幸运的是,您可以在git log中组合-S-m选项,并且它按预期工作。

1
不幸的是,在git 2.15.1.windows.2上,这对我似乎无法正常工作。输出包括合并提交,这些提交似乎没有改变给定的文本——-G也是如此。 - Robin Green
@RobinGreen 你看过 git log -m -p 的输出吗?有意义吗?git log -m -S 的结果是否与 git log -m -p 的输出一致? - Leon
谢谢你的回答,这非常有用!我还没有接受它,因为它没有涵盖git bisect。此外,您可能希望将命令git log -m --all -S TERM放在您的答案顶部,因为它目前被埋在底部并且没有完全拼写出来。 - Rich
@Rich 同意。已更新。 - Leon
@Leon:是的,文件已经被修改了。或者说:相对于合并父版本A,文件保持不变。但是,相对于父版本B,它已经被修改了。合并处理是棘手的。 - Jidehem
显示剩余2条评论

3

使用git bisect的解决方案

git bisect start $badCommit $goodCommit
git bisect run bash -c "! git merge-base --is-ancestor $goodCommit HEAD || git grep -q $TERM"
bit bisect reset

注意:为了简单起见,此解决方案使用git bisect run。您也可以在“交互”模式下使用git bisect。请参阅下面的说明部分。

主要思想

该思想是将二分算法分析的提交限制在祖先路径中的提交上。

这个思想是由CB Baileythis comment中提出的,尽管我没有找到使用git rev-list的方法。

说明

关于git bisect的部分,解释有点棘手。 它基于二分算法的工作原理。 该算法假设所有好的提交的祖先都是好的。 因此,在测试git bisect中的特定提交时,您必须将不是好提交的后代标记为好。当仅使用简单的grep函数时,通常情况下并非如此。 您可以使用git merge-base --is-ancestor $goodCommit HEAD来判断提交是否是另一个提交的后代(更多详细信息请参见如何判断一个提交是否是另一个提交的祖先(或反之亦然)?检查一个提交是否是另一个提交的祖先)。

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