Intellij Idea 我可以配置git责备来忽略某些提交吗?想一劳永逸地修复git责备吗

4uqofj5v  于 2023-01-25  发布在  Git
关注(0)|答案(2)|浏览(130)

我在一个git责备已经被有效地打破的存储库中。
在git责备中我想忽略两个提交。

  • 提交1销毁了 * 大量 * 文件。
  • 提交2立即恢复了提交1。

现在每次我git责备一行代码时,我看到的都是[commit 2]的作者,而不是真正的逻辑作者。
我最终不得不执行git log [file in question],或者this question中列出的另一个解决方案。
每当我使用Intellij中的Annotate特性时,这两个提交都会让我感到难过(这基本上是git的过错)。
以前有没有人在不改写历史的情况下解决过这个问题?

m528fe3b

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:

---O---A---X---B---C---D---Y---E---F

提交XY都触及特定行,而其他提交则没有:

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

Y: "Remove camelcase"
-MyFunc(1, 2, 3);
+my_func(1, 2, 3);

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行有这样的语句:

commit-a 11) #include "a.h"
commit-b 12) #include "b.h"

提交X(我们将忽略它),交换这些行:

commit-X 11) #include "b.h"
commit-X 12) #include "a.h"

我们可以把这个blame条目传递给父提交,但是第11行将被分配给提交A,即使"include b. h"来自提交B
指责机制将查看第11行的父视图。
ignore_blame_entry()被设置为允许用于猜测每行错误的替换算法。
任何不属于父提交的行都将继续被归咎于被忽略的提交,就像该提交没有被忽略一样。
即将发布的补丁能够检测这些行并在blame输出中标记它们。
现有算法很简单:将每一行归咎于父比较块中的相应行。
任何超过这一点的线条都与目标保持一致。
例如,一个被忽略提交的父提交在第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

提交"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

另外提交X网络两行:十三和十四。
当前的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

注意第12行被归咎于B,尽管Bnew_func_2()的提交,而不是new_func_1()
即使guess_line_blames()在父对象中找到一行,它仍然可能是不正确的。
git blame新文档:

--ignore-rev <rev>::

在分配责任时忽略修订所做的更改,就像更改从未发生过一样。
被忽略的提交所更改或添加的行将被归咎于更改该行或附近行的前一个提交。
可以多次指定此选项以忽略多个修订。

--ignore-revs-file <file>:

忽略file中列出的修订,这些修订必须与fsck.skipList相同。
此选项可以重复,并且这些文件将在使用blame.ignoreRevsFile配置选项指定的任何文件之后处理。
空文件名""将清除以前处理过的文件中的转速列表。
git config新文档:

blame.ignoreRevsFile:

忽略文件中列出的修订,每行一个未缩写的对象名,格式为git blame
空白和以#开头的注解将被忽略。
此选项可以重复多次。
空文件名将重置忽略的修订列表。
此选项将在命令行选项--ignore-revs-file之前处理。
由于线检测并不总是完美的:

blame:为被忽略或无过错行的输出添加配置选项

当忽略提交时,由于启发式算法的不准确性,被指责的提交可能不对更改负责。
用户可能想知道特定行何时具有潜在的不准确指责。
此外,guess_line_blames()可能无法找到被忽略的提交所触及的给定行的任何父提交。
那些"无可指责"的代码行仍然被归咎于一个被忽略的提交。
用户可能想知道某行是否是无可指责的,这样他们就不会花时间调查他们知道是无趣的提交。
这个补丁添加了两个配置选项,用于在输出中标记这两种类型的行。
第一个选项可以通过指定blame.markIgnoredLines来标识忽略的线。

    • 设置此选项时,每个被归咎于被忽略提交以外的提交的归咎行都标记为"?"**。

例如:

278b6158d6fdb (Barret Rhoden  2016-04-11 13:57:54 -0400 26)

显示为:

?278b6158d6fd (Barret Rhoden  2016-04-11 13:57:54 -0400 26)

其中"?"被放置在提交之前,并且散列具有少一个字符。
有时我们甚至无法猜测哪个祖先commit触及了某行。

    • 这些线是"无可指责的"。

第二个选项blame.markUnblamableLines将用"*"**标记该行。
例如,假设我们忽略了e5e8d36d04cbe,但是我们不能将此行归咎于另一个提交:

e5e8d36d04cbe (Barret Rhoden  2016-04-11 13:57:54 -0400 26)

显示为:

*e5e8d36d04cb (Barret Rhoden  2016-04-11 13:57:54 -0400 26)

当这些配置选项一起使用时,被忽略的提交所触及的每一行都将被标记为'?'或'*'。
这意味着git config手册页现在具有:

blame.markUnblamables:

git blame的输出中,用"*"标记被忽略的修订版更改的行,我们无法将其归因于另一个提交。

blame.markIgnoredLines:

git blame的输出中,用'?'标记被我们归因于另一个提交的忽略修订版更改的行。
最后,为了改进git blame线检测:

blame:添加指纹启发式算法以匹配忽略的行

这个算法将用一个在父版本的文件中找到可能的候选行的算法来替换用于从被忽略的提交中识别行的启发式算法。
实际的替换发生在即将到来的提交中。
旧的启发式方法只是将目标中的行分配给父对象中相同的行号(加上偏移量),新函数使用指纹算法来检测行之间的相似性。
新的启发式设计用于精确匹配由clang-format和clang-tidy等格式化工具机械地做出的更改。
这些工具可以进行更改,例如将行拆分以符合字符限制,或者更改标识符以符合命名约定。
启发式并不旨在匹配更广泛的重构更改,在这种情况下可能会给出误导性的结果。
在大多数情况下,格式化工具会保留行排序,因此启发式算法会针对此类情况进行优化。(某些类型的更改会对行进行重新排序,例如排序会保持行内容相同,git blame -M选项已经可以用于解决此问题)。
依赖于排序是有利的原因是由于源代码经常重复相同的字符序列,例如在一行上声明标识符并且在随后的几行上使用该标识符。
这意味着线条看起来非常相似,这在进行模糊匹配时会出现问题。依赖于排序可以为我们提供额外的线索来指向真正的匹配。

    • 启发式算法一次只对一个diff块更改进行操作**。
    • 它为更改两侧的每一行创建"指纹"**。

fingerprint在struct fingerprint的注解中有详细描述,但本质上是一行中字符对的多重集合。

  • 试探法首先识别目标条目中其指纹与父条目中的行指纹最清楚匹配的行。

在指纹完全匹配的情况下,行的位置被用作平局决胜。-试探法锁定最佳匹配,并且从父条目中行的指纹中减去目标条目中行的指纹,以防止在该行的相同部分上匹配其它行。

  • 然后递归地对匹配之前的块的部分重复该过程,然后对匹配之后的块的部分重复该过程。

这里有一个指纹识别带来的不同的例子。
考虑一个包含两次提交的文件:

commit-a 1) void func_1(void *x, void *y);
   commit-b 2) void func_2(void *x, void *y);

在提交“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);

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

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);

其中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);

注意,行2可以与commit-acommit-b匹配,因为它与这两条行同等相似,但是与commit-a匹配,因为它作为新行范围的一部分的位置与作为旧行范围的一部分的commit-a更相似。
行4也同样类似于这两行,但是由于它出现在将首先匹配的行3之后,所以它不能与更早的行匹配。
更多示例,请参见t/t8014-blame-ignore-fuzzy.sh,其中包含示例父文件和目标文件以及父文件中必须匹配的行号。

qlfbtfca

qlfbtfca2#

如果它确实立即被恢复,那么可以使用git replace --edit $comment2将commit1父节点伪装成它的父节点。

相关问题