启用git rerere有什么缺点吗?

131

我已经阅读了关于git的rerere功能的各种信息,正在考虑启用它。

git rerere功能是一个有点隐藏的特性。名称代表“reuse recorded resolution”,正如名称所示,它允许您要求Git记住您如何解决冲突,以便下次遇到相同的冲突时,Git可以自动解决它。

https://git-scm.com/book/zh/v2/Git-工具-rerere

但我没有看到任何人提到使用rerere可能出现的问题。

我必须假设存在缺点,否则它可能已默认启用。因此,启用rerere会有什么缺点?它可能引起哪些不会发生的潜在问题?


当启用自动rerere并应用先前的解决方案时,它是否会显示消息?如果是,它看起来像什么?谢谢! - joeytwiddle
1
根据这篇文章,它的格式应该是Resolved 'index.html' using previous resolution. - user82216
5个回答

84
如果您错误地合并,然后放弃它,再次进行“相同”的合并,那么它仍然是不正确的。但是您可以忘记已记录的解决方法。从文档中得知:

git rerere forget <pathspec>

这将重置rerere为当前冲突记录的<pathspec>中记录的冲突解决方案。

请注意,在特定路径上使用它;您不想在所有记录的解决方案中都清除它们。 (forget没有参数已经不建议使用,以免您这样做,除非您显式请求git rerere forget .。)
但是,如果您没有考虑到这一点,您可能会很容易地将该不正确的合并放入您的历史记录中...

17
这就是为什么 rerere 会把有冲突的文件标记为未合并,这样你就必须要手动添加它们(希望在检查/测试后),然后再提交。如果需要的话,你可以始终使用 git checkout -m <path> 命令来检出原始的有冲突的版本并重新解决冲突。 - Cascabel
2
那很有道理!听起来你需要一个新的别名。 - Cascabel
7
我认为这可能是主要问题。启用rerere会增加意外出现错误的可能性。你中止(或通过从历史记录中删除来撤销)的合并仍然可能会在以后回来困扰你。基本上,它引入了第二种与实际历史图不相关的历史机制。 - Ryan C. Thompson
3
@RyanThompson 中止的合并不会影响 rerere。(我常常希望它们能够影响——有时我因为设置错误而中止了合并,然后在正确设置后需要做完全相同的决议。)至于从历史记录中删除合并,你为什么要这样做呢? - Marnen Laibow-Koser

50

正如 J. C. Hamano 在他的文章 "Fun with rerere"(我加粗了)中所提到的:

  • Rerere 记住了您选择解决冲突区域的方式;
  • Rerere 还记得您在冲突区域之外进行的语义更改调整;
  • Rerere 可以重用先前的解决方案,即使您正在合并两个与您早期解决的内容不同的分支

即使使用 rerere 很长时间的人也经常忽略最后一点。

因此,如果您在内容上激活了 rerere,由于最后一点,您可能会得到令人惊讶或困惑的合并解决方案。


另一个缺点是当你激活了commit.gpgSign时,rerere会要求你输入GPG签名的PIN码。
这个问题已经在Git 2.38 (Q3 2022)中得到解决。

18
冲突的代码块仍然需要匹配;这很难产生错误结果。 - Cascabel
还有 git rerere gc 可以忘记旧的解决方案。时间范围越短,误击的概率就越小。 - gavenkoa
2
@gavenkoa True (https://git-scm.com/docs/git-rerere#Documentation/git-rerere.txt-emgcem):默认情况下,未解决的冲突超过15天和已解决的冲突超过60天将被修剪。 - VonC

5

我已经全局启用了rerere。实际上,我没有注意到任何问题,通常它似乎使我的生活更加轻松。


5
一样。使用2年多没出现过问题。 - Andrey Tarantsov
@AndreyTarantsov,12年使用后有任何更新吗? - manish ma
1
@manishma,我不是安德烈,但我仍然喜欢rerere。 - Marnen Laibow-Koser

3

我在gitk中挑选了一个只包含二进制文件的提交。由于冲突,cherrypick失败了(想想也是很自然的)。我解决了冲突并保留了cherry pick。后来我惊讶地发现,在另一个已经rebase的分支中,我的dll文件没有正常工作——后来我发现它们没有被带入rebase中(我猜测是因为自动冲突解决)。所以这是我遇到的唯一一种情况(启用rerere),遇到了直觉上不符合预期(尽管我确定是完全一致的)的行为。


1
解决方法:git rerere forget path/to/compiled/bin.dll - Mr_and_Mrs_D
在最初的情况下,我遇到了冲突,不是在挑选樱桃上,而是在变基上,但我认为这没有什么区别。 - Mr_and_Mrs_D

1
根据这个问题和答案Rerere不会记录与冲突文件中不同的部分。可能发生这种情况的一个例子是在重构文件时,某些行被提取并移动到另一个文件中,随后冲突的提交会修改这些行。在这种情况下,解决方案将涉及在新文件中进行更改。
示例
初始状态
文件a:
const foo = [
    'line 1',
    'line 2',
    'line 3',
];
// ...
const str = foo.join("\n");

重构

新文件 b:

const foo = [
    'line 1',
    'line 2',
    'line 3',
];

重构文件 a:
// ...
const str = b.foo.join("\n")

冲突的更改

在另一个分支中将a更改为:

const foo = [
    'line 1',
    'line 2',
    'new line',
    'line 3',
];
// ...
const str = foo.join("\n");

解决方案

解决方案保留了文件a中重构后的内容,并将新行添加到文件b中。然而,请注意,Rerere只会重新应用解决方案到文件a,因为在初始解决方案过程中它遇到了冲突,而文件b则没有遇到任何冲突。


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