我在一个git责备已经被有效地打破的存储库中。
在git责备中我想忽略两个提交。
- 提交1销毁了 * 大量 * 文件。
- 提交2立即恢复了提交1。
现在每次我git责备一行代码时,我看到的都是[commit 2]的作者,而不是真正的逻辑作者。
我最终不得不执行git log [file in question]
,或者this question中列出的另一个解决方案。
每当我使用Intellij中的Annotate特性时,这两个提交都会让我感到难过(这基本上是git的过错)。
以前有没有人在不改写历史的情况下解决过这个问题?
2条答案
按热度按时间m528fe3b1#
每当我使用IntelliJ中的Annotate特性时,这两个提交都会让我感到难过(这基本上是git的错)。
以前有没有人在不改写历史的情况下解决过这个问题?
2019年第三季度前,无
但是在Git 2.23中,你可以命令git blake忽略这两个有问题的提交(IntelliJ的"注解"功能可能需要一段时间才能跟上)。
Michael Platings评论:
git blame --ignore-rev
的工作假设是指定的提交做了一个无趣的改变(例如重新格式化)。不幸的是,删除和添加文件都是相当剧烈的更改,因此
--ignore-rev
在这里没有帮助。也就是说,
git blame
现在可以忽略提交(甚至在这个特定的例子中可能不会)。一般来说,自Git 2.23:
"
git blame
"学会了"ignore"历史记录中的提交,这些提交的影响(以及它们的存在)被忽略。你可以在你的
git config
中注册它!你甚至不需要在每个git blame
调用中传递这些提交。参见commit 78fafbb(2019年6月30日)和commit 1d028dc(2019年6月20日)。
参见Jeff King (
peff
)的commit 07a54dc(2019年6月28日)。参见第commit f0cbe74、第commit a07a977(2019年6月20日)和第commit 1fc7338、第commit 8934ac8、第commit ae3f36d、第commit 55f808f、第commit f93895f、第commit 24eb33e(2019年5月15日)。
(由Junio C Hamano --
gitster
--合并至commit 209f075,2019年7月19日)blame
:添加忽略提交及其更改的功能在指责文件时,进行格式更改或函数重命名的提交通常不受关注。
用户可能认为这样的提交是"不感兴趣的",并且在分配责备时想要忽略它及其改变。
例如,假设一个文件包含以下git history/rev-list:
提交
X
和Y
都触及特定行,而其他提交则没有:git-blame
将此更改归咎于Y
。我希望能够忽略
Y
:提交的存在及其所做的任何更改。这与
-S rev-list
不同,-S rev-list
指定了要处理的提交列表。我们仍然会处理
Y
,但只是不要让指责"坚持"。--ignore-rev=rev
版本的功能**。它们可以指定一组rev的完整对象名称的文件,例如SHA-1散列,每行一个。
可以使用
blame.ignoreRevsFile
配置选项或--ignore-revs-file=file
指定单个文件。配置选项和命令行选项都可以重复多次。
空文件名
""
将清除先前处理文件中的转速列表。配置选项在命令行选项之前处理。
对于一个典型的用例,项目将维护包含执行批量重定格式的提交的修订的文件,并且他们的用户可以选择忽略该文件中的所有提交。
此外,用户可以使用
--ignore-rev
选项进行一次性调查。回到上面的例子,
X
是对函数的实质性更改,但不是用户感兴趣的更改。用户检查了
X
,但希望找到该行之前的更改-可能是引入该函数调用的提交。要做到这一点,我们不能简单地从rev-list中删除所有被忽略的提交。
我们需要对
Y
引入的更改进行比较,以便忽略它们。我们让责任传递给
Y
,就像正常处理时一样。当
Y
是目标时,我们确保Y
不 * 保留 * 任何指责。Y
负责的任何更改都传递给其父节点。注意,我们对所有的替罪羊(父节点)进行一次传递,以尝试正常地传递责任;我们不知道是否需要忽略这个提交,直到我们检查了所有的父节点。在我们找到一个包含影响这些行的diff块的提交之前,blame_entry将沿着树向上传递。
一个问题是被忽略的提交 * 确实 * 做了一些改变,并且没有通用的解决方案来找到父提交中对应于被忽略提交中给定行的行。
这使得在被忽略的提交的diff中很难正确地属性化一个特定的行。
例如,一个被忽略提交的父提交在第11行有这样的语句:
提交
X
(我们将忽略它),交换这些行:我们可以把这个blame条目传递给父提交,但是第11行将被分配给提交A,即使"include b. h"来自提交
B
。指责机制将查看第11行的父视图。
ignore_blame_entry()
被设置为允许用于猜测每行错误的替换算法。任何不属于父提交的行都将继续被归咎于被忽略的提交,就像该提交没有被忽略一样。
即将发布的补丁能够检测这些行并在blame输出中标记它们。
现有算法很简单:将每一行归咎于父比较块中的相应行。
任何超过这一点的线条都与目标保持一致。
例如,一个被忽略提交的父提交在第11行有这样的语句:
提交"X"后,我们有:
另外提交
X
网络两行:十三和十四。当前的
guess_line_blames()
算法不会将这些属性赋予父进程,因为父进程的diff块只有两行,而不是四行。当我们忽略当前算法时,我们得到:
注意第12行被归咎于
B
,尽管B
是new_func_2()
的提交,而不是new_func_1()
。即使
guess_line_blames()
在父对象中找到一行,它仍然可能是不正确的。git blame
新文档:在分配责任时忽略修订所做的更改,就像更改从未发生过一样。
被忽略的提交所更改或添加的行将被归咎于更改该行或附近行的前一个提交。
可以多次指定此选项以忽略多个修订。
忽略
file
中列出的修订,这些修订必须与fsck.skipList
相同。此选项可以重复,并且这些文件将在使用
blame.ignoreRevsFile
配置选项指定的任何文件之后处理。空文件名
""
将清除以前处理过的文件中的转速列表。git config
新文档:忽略文件中列出的修订,每行一个未缩写的对象名,格式为
git blame
。空白和以
#
开头的注解将被忽略。此选项可以重复多次。
空文件名将重置忽略的修订列表。
此选项将在命令行选项
--ignore-revs-file
之前处理。由于线检测并不总是完美的:
blame
:为被忽略或无过错行的输出添加配置选项当忽略提交时,由于启发式算法的不准确性,被指责的提交可能不对更改负责。
用户可能想知道特定行何时具有潜在的不准确指责。
此外,
guess_line_blames()
可能无法找到被忽略的提交所触及的给定行的任何父提交。那些"无可指责"的代码行仍然被归咎于一个被忽略的提交。
用户可能想知道某行是否是无可指责的,这样他们就不会花时间调查他们知道是无趣的提交。
这个补丁添加了两个配置选项,用于在输出中标记这两种类型的行。
第一个选项可以通过指定
blame.markIgnoredLines
来标识忽略的线。?
"**。例如:
显示为:
其中"
?
"被放置在提交之前,并且散列具有少一个字符。有时我们甚至无法猜测哪个祖先commit触及了某行。
第二个选项
blame.markUnblamableLines
将用"*
"**标记该行。例如,假设我们忽略了e5e8d36d04cbe,但是我们不能将此行归咎于另一个提交:
显示为:
当这些配置选项一起使用时,被忽略的提交所触及的每一行都将被标记为'
?
'或'*
'。这意味着
git config
手册页现在具有:在
git blame
的输出中,用"*"标记被忽略的修订版更改的行,我们无法将其归因于另一个提交。在
git blame
的输出中,用'?
'标记被我们归因于另一个提交的忽略修订版更改的行。最后,为了改进
git blame
线检测:blame
:添加指纹启发式算法以匹配忽略的行这个算法将用一个在父版本的文件中找到可能的候选行的算法来替换用于从被忽略的提交中识别行的启发式算法。
实际的替换发生在即将到来的提交中。
旧的启发式方法只是将目标中的行分配给父对象中相同的行号(加上偏移量),新函数使用指纹算法来检测行之间的相似性。
新的启发式设计用于精确匹配由clang-format和clang-tidy等格式化工具机械地做出的更改。
这些工具可以进行更改,例如将行拆分以符合字符限制,或者更改标识符以符合命名约定。
启发式并不旨在匹配更广泛的重构更改,在这种情况下可能会给出误导性的结果。
在大多数情况下,格式化工具会保留行排序,因此启发式算法会针对此类情况进行优化。(某些类型的更改会对行进行重新排序,例如排序会保持行内容相同,
git blame -M
选项已经可以用于解决此问题)。依赖于排序是有利的原因是由于源代码经常重复相同的字符序列,例如在一行上声明标识符并且在随后的几行上使用该标识符。
这意味着线条看起来非常相似,这在进行模糊匹配时会出现问题。依赖于排序可以为我们提供额外的线索来指向真正的匹配。
fingerprint在
struct fingerprint
的注解中有详细描述,但本质上是一行中字符对的多重集合。在指纹完全匹配的情况下,行的位置被用作平局决胜。-试探法锁定最佳匹配,并且从父条目中行的指纹中减去目标条目中行的指纹,以防止在该行的相同部分上匹配其它行。
这里有一个指纹识别带来的不同的例子。
考虑一个包含两次提交的文件:
在提交“
X
”之后,我们有:当我们用旧算法忽略责备时,我们得到:
其中
commit-b
被归咎于2而不是3。使用指纹算法,我们可以得到:
注意,行2可以与
commit-a
或commit-b
匹配,因为它与这两条行同等相似,但是与commit-a
匹配,因为它作为新行范围的一部分的位置与作为旧行范围的一部分的commit-a
更相似。行4也同样类似于这两行,但是由于它出现在将首先匹配的行3之后,所以它不能与更早的行匹配。
更多示例,请参见
t/t8014-blame-ignore-fuzzy.sh
,其中包含示例父文件和目标文件以及父文件中必须匹配的行号。qlfbtfca2#
如果它确实立即被恢复,那么可以使用
git replace --edit $comment2
将commit1父节点伪装成它的父节点。