我可以配置git blame使其始终忽略某些提交吗?想要一劳永逸地修复git怪

Mer*_*ith 5 git version-control intellij-idea

我在一个有效地解决git怪的仓库中。

我想在git blame中忽略两个提交。

  • 提交1破坏了很多文件。
  • 提交2立即还原为提交1。

现在,每次我怪罪一行时,我都会看到[commit 2]的作者,而不是真正的逻辑作者。

我最终不得不做一个git log [file in question]替代方案,或者这个问题中列出的另一种解决方案。

每当我使用Intellij中的Annotate功能(基本上是git blame)时,这两个提交使我感到很难过。

有没有人在不重写历史的情况下解决过这个问题?

Von*_*onC 12

每当我使用Intellij中的Annotate功能(基本上是git blame)时,这两个提交使我感到很难过。
有没有人在不重写历史的情况下解决过这个问题?

在2019年第三季度之前,没有
但是使用Git 2.23,您将能够指示git blame 忽略这两个有问题的提交。(IntelliJ“注释”功能可能需要一段时间才能赶上)

迈克尔·普拉丁斯(Michael Plates) 评论

git blame --ignore-rev在指定的提交进行了无意义的更改(例如重新格式化)的假设下工作。
不幸的是,删除和添加文件都是相当大的更改,因此--ignore-rev这里无济于事。

话虽如此,git blame现在可以忽略提交(即使在这种情况下也可以)。

通常,从Git 2.23开始:

git blame”学会“ 忽略 ”历史中的提交,其作用(以及它们的存在)被忽略。

您可以在自己的网站上注册git config!您甚至不需要在每次git blame调用时在参数中传递这些提交。

看看提交78fafbb(2019年6月30日),以及提交1d028dc(2019年6月20日)由迈克尔镀层(``)
参见Jeff King(提交07a54dc(2019年6月28日。 见提交f0cbe74提交a07a977(二○一九年六月二十日),以及提交1fc7338提交8934ac8提交ae3f36d提交55f808f提交f93895f提交24eb33e由(2019 5月15日)巴瑞特Rhoden( ) (由Junio C Hamano合并--peff
brho
gitster承诺209f075,2019年7月19日)

blame:添加忽略提交及其更改的功能

归咎于文件时,进行格式更改或函数重命名的提交通常并不有趣。
用户可能会将这样的提交视为“不感兴趣”,并希望在分配责任时忽略其更改。

例如,假设文件具有以下git历史记录/ rev-list:

---O---A---X---B---C---D---Y---E---F
Run Code Online (Sandbox Code Playgroud)

提交,X并且Y两者都碰到特定的一行,而其他提交则不:

X: "Take a third parameter"
-MyFunc(1, 2);
+MyFunc(1, 2, 3);

Y: "Remove camelcase"
-MyFunc(1, 2, 3);
+my_func(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

git-blameY为变化负责。
我希望能够忽略Y:提交的存在及其所做的任何更改。
这与有所不同-S rev-list,后者指定了要归咎于处理的提交列表。
我们仍然会处理Y,但不要让责备“坚持下去”。

该补丁为用户提供了忽略修订的功能--ignore-rev=rev,该修订可以重复
他们可以指定一组具有revs完整对象名称的文件,例如SHA-1哈希,每行一个。
单个文件可以使用blame.ignoreRevFileconfig选项或来指定--ignore-rev-file=file
config选项和命令行选项都可以重复多次。

空文件名将""清除先前处理过的文件的转速列表。
配置选项在命令行选项之前处理。

对于典型的用例,项目将维护包含执行批量重新格式化的提交的修订的文件,并且其用户可以选择忽略该文件中的所有提交。

此外,用户可以使用该--ignore-rev选项进行一次性调查。
回到上面的示例,X是对功能的实质性更改,但不是用户感兴趣的更改。
用户检查了X,但想找到对该行的先前更改-可能是引入了该函数调用的提交。

为了使此工作有效,我们不能简单地从rev-list中删除所有忽略的提交。
我们需要区分引入的更改,Y以便我们可以忽略它们。就像正常处理时一样,
我们让责备传递给Y
如果Y是目标,我们要确保Y保留任何指责。负责传递给其父级的
任何更改Y。注意,我们一次通过了所有替罪羊(父母)以试图正常地怪罪;在我们检查了所有父母之前,我们不知道是否需要忽略提交。

blame_entry将沿树向上传递,直到我们找到具有影响这些行的差异块的提交为止。

一个问题是被忽略的提交确实做了一些更改,并且没有通用的解决方案来找到与被忽略的提交中的给定行相对应的父提交中的行。
这使得很难在忽略的提交的差异中正确地分配特定的行。

例如,被忽略的提交的父级具有此名称,例如在第11行:

commit-a 11) #include "a.h"
commit-b 12) #include "b.h"
Run Code Online (Sandbox Code Playgroud)

Commit X(我们将忽略)交换了以下几行:

commit-X 11) #include "b.h"
commit-X 12) #include "a.h"
Run Code Online (Sandbox Code Playgroud)

我们可以通过该怪进入到父,但线11将归于犯,即使“包括BH”的承诺来B
怪机制将在第11行上查看父文件的视图。

ignore_blame_entry()设置为允许使用其他算法来猜测每行归咎。
任何未归于父代的行都将继续归咎于忽略的提交,就像未忽略该提交一样。
即将到来的补丁可以检测到这些行并将其标记在非正常输出中。

现有算法很简单:将每一行归咎于父级的diff块中的相应行。
超出该范围的任何行均与目标保持一致。

例如,被忽略的提交的父级具有此名称,例如在第11行:

commit-a 11) void new_func_1(void *x, void *y);
commit-b 12) void new_func_2(void *x, void *y);
commit-c 13) some_line_c
commit-d 14) some_line_d
Run Code Online (Sandbox Code Playgroud)

提交“ X”后,我们有:

commit-X 11) void new_func_1(void *x,
commit-X 12)                 void *y);
commit-X 13) void new_func_2(void *x,
commit-X 14)                 void *y);
commit-c 15) some_line_c
commit-d 16) some_line_d
Run Code Online (Sandbox Code Playgroud)

提交X网另外两行:13和14。
当前guess_line_blames()算法不会将它们归于父级,父级的diff块只有两行,而不是四行。

当我们忽略当前算法时,将得到:

commit-a 11) void new_func_1(void *x,
commit-b 12)                 void *y);
commit-X 13) void new_func_2(void *x,
commit-X 14)                 void *y);
commit-c 15) some_line_c
commit-d 16) some_line_d
Run Code Online (Sandbox Code Playgroud)

需要注意的是第12行被归咎于B,虽然B是犯了new_func_2(),没有new_func_1()
即使guess_line_blames()在父级中找到一行,它也可能仍然不正确。


git blame新文件

--ignore-rev <rev>::
Ignore changes made by the revision when assigning blame, as if the
change never happened.  Lines that were changed or added by an ignored
commit will be blamed on the previous commit that changed that line or
nearby lines.  This option may be specified multiple times to ignore
more than one revision.

--ignore-revs-file <file>:
Run Code Online (Sandbox Code Playgroud)

忽略中列出的修订file,修订的格式fsck.skipList必须与相同
可以重复执行此选项,并且将在使用blame.ignoreRevsFileconfig选项指定的任何文件之后处理这些文件。
空文件名""将会清除以前处理过的文件的转速列表。

git config新文件

blame.ignoreRevsFile:
Run Code Online (Sandbox Code Playgroud)

忽略文件中列出的修订,该修订中的每行一个未缩写的对象名称git blame
空格和以开头的注释将#被忽略。
此选项可以重复多次。
空文件名将重置忽略的修订列表。
此选项将在命令行选项之前处理--ignore-revs-file


由于行检测并不总是完美的:

blame:添加配置选项以输出被忽略或不可指义的行

当忽略提交时,由于我们的启发式方法的不准确性,被指责的提交可能不负责更改。
用户可能想知道特定行何时可能有不正确的责任。

此外,guess_line_blames()可能无法找到被忽略的提交触及的给定行的任何父提交。
这些“不可指责”的行仍然归咎于被忽略的提交。
用户可能想知道行是否不可指责,以便他们不花时间研究他们不感兴趣的提交。

此补丁添加了两个配置选项,以在怪输出中标记这两种类型的线。

第一个选项可以通过指定来识别被忽略的行blame.markIgnoredLines
设置此选项时,除被忽略的提交以外,其他所有应归因于提交的非标行都标有' ?'

例如:

278b6158d6fdb (Barret Rhoden  2016-04-11 13:57:54 -0400 26)
Run Code Online (Sandbox Code Playgroud)

显示为:

?278b6158d6fd (Barret Rhoden  2016-04-11 13:57:54 -0400 26)
Run Code Online (Sandbox Code Playgroud)

其中在?提交之前放置了' ',并且哈希少了一个字符。

有时我们甚至无法猜测什么祖先触动了一条线。
这些行是“不可言喻的”。
第二个选项blame.markUnblamableLines将用' *' 标记行

例如,假设我们忽略e5e8d36d04cbe,但是我们无法将这一行归咎于另一次提交:

e5e8d36d04cbe (Barret Rhoden  2016-04-11 13:57:54 -0400 26)
Run Code Online (Sandbox Code Playgroud)

显示为:

*e5e8d36d04cb (Barret Rhoden  2016-04-11 13:57:54 -0400 26)
Run Code Online (Sandbox Code Playgroud)

当这些配置选项一起使用时,被忽略的提交触及的每一​​行都将标记为“ ?”或“ *”。

这意味着git config手册页现在具有:

blame.markUnblamables: 
Run Code Online (Sandbox Code Playgroud)

用忽略的修订标记更改的行,我们不能将其归因于输出中带有'*'的另一个提交git blame

blame.markIgnoredLines:
Run Code Online (Sandbox Code Playgroud)

标记被忽略的修订所更改的行,我们将其归因于另一个提交,并?在的输出中以“ '”表示git blame


最后,要改善git blame行检测:

blame:添加指纹试探法以匹配被忽略的行

该算法将用一种在文件的父版本中查找可能的候选行的启发式算法替换用于从忽略的提交中识别行的启发式算法。
实际的替换发生在即将到来的提交中。

旧的启发式方法只是简单地将目标中的行分配给父级中的相同行号(加上偏移量)。新功能使用指纹算法来检测线之间的相似性。

新的启发式设计旨在精确匹配通过格式化工具(例如clang-format和clang-tidy)进行的机械更改。
这些工具进行了一些更改,例如将行拆分以适合字符限制,或者更改标识符以符合命名约定。
启发式方法无意匹配更广泛的重构更改,在这种情况下可能会产生误导性的结果。

在大多数情况下,格式化工具会保留行顺序,因此针对此类情况优化了启发式方法。(某些类型的更改git blame -M会对行进行重新排序,例如排序使行内容保持一致,该选项已经可以用来解决此问题)。
依赖排序的优势在于源代码经常重复相同的字符序列,例如在一行上声明一个标识符,并在随后的几行上使用该标识符。
这意味着线条看起来可能非常相似,这在进行模糊匹配时会出现问题。依靠订购可以为我们提供更多线索,以指向真正的匹配。

启发式算法一次处理一个差异块
它为更改的每一侧的每一行创建一个“指纹”

指纹的注释struct fingerprint中详细描述了指纹,但指纹实际上是一行中字符对的多集。

  • 启发式方法首先在目标条目中标识其指纹与父条目中的行指纹最明显匹配的行。
    在指纹完全匹配的情况下,将线条的位置用作平局。-试探法锁定最佳匹配,并从父条目中的行的指纹中减去目标条目中的行的指纹,以防止其他行与该行的相同部分匹配。
  • 然后,它在匹配之前在块的部分上递归地重复该过程,然后在匹配之后在块的部分上递归地重复该过程。

这是指纹差异的一个示例。
考虑具有两次提交的文件:

    commit-a 1) void func_1(void *x, void *y);
    commit-b 2) void func_2(void *x, void *y);
Run Code Online (Sandbox Code Playgroud)

提交' X'之后,我们有:

    commit-X 1) void func_1(void *x,
    commit-X 2)             void *y);
    commit-X 3) void func_2(void *x,
    commit-X 4)             void *y);
Run Code Online (Sandbox Code Playgroud)

当我们用旧算法责怪忽略时,我们得到:

    commit-a 1) void func_1(void *x,
    commit-b 2)             void *y);
    commit-X 3) void func_2(void *x,
    commit-X 4)             void *y);
Run Code Online (Sandbox Code Playgroud)

commit-b被指责为2,而不是3。

使用指纹算法,我们得到:

    commit-a 1) void func_1(void *x,
    commit-a 2)             void *y);
    commit-b 3) void func_2(void *x,
    commit-b 4)             void *y);
Run Code Online (Sandbox Code Playgroud)

注线2可与任一被匹配commit-acommit-b作为其同样类似于两行,但具有匹配commit-a,因为其作为新线路范围的一小部分的位置更类似于commit-a作为旧线范围的一小部分。
第4行也与这两行类似,但是它出现在第3行之后,该行将首先匹配,因此无法与较早的行匹配。

有关更多示例,请参见t/t8014-blame-ignore-fuzzy.sh其中包含示例父文件和目标文件以及父文件中必须匹配的行号。

  • 如果有人也希望获得 Bitbucket 的支持,这里是功能请求的链接:https://jira.atlassian.com/browse/BSERV-12730 (2认同)