告诉git跟随移动的内容(而不仅仅是移动的文件)



重构源代码时,有时需要在文件中移动大块文本,甚至移动到新文件中。您创建一个分支refactored并提交:

$git checkout master
$git branch refactored
$git checkout refactored
<move code around>
$git commit -m "refactored code"

然而,人们可能会在旧的预重构分支之上进行提交,更改被移动的代码:

$git checkout master
<change code that was moved elsewhere on branch refactored>
$git commit -m "bugfix"

在分支refactored上,您需要合并master:中所做的更改

$git checkout refactored
$git merge master
<giant merge conflict>

这会导致一个大的合并冲突。如果有一种方法可以告诉git内容只是被移动了,那么应该可以自动合并。

更糟糕的是,即使在解决了冲突并提交之后,git仍然无法使用该解决方案来计算进一步的合并:

<fix conflicts>
$git commit -m "merge master into refactored"
$git checkout master
<change more code>
$git commit -m "bugfix2"
$git checkout refactored
$git merge master
<another giant merge conflict>

这是可以避免的吗?我试过git rerere,但它无法解决这里的冲突。git是否可以将移动文本块视为实际移动,而不是删除和插入?如果不能,如果您需要将两个并行分支保持一段时间,那么最大限度地减少合并冲突的最佳方法是什么?

虽然这对于移动一个完整文件的内容来说很容易,但我找不到关于只移动其部分或在同一文件内移动的信息。

此外,如果有解决方案,那么git blame在重构的密码它是指向重构提交,还是忽略它?有没有办法做到晚一点?

如果有人感兴趣,我已经放了一个base64编码的tar.gz的(非常小的)存储库,我正在使用它来测试pastebin

潜在解决方案

一个潜在的解决方案可能是通过在预重构的分支中应用(自动)编辑的补丁来执行合并。有没有为此开发的软件?使用这种方法,我想,由于这对git是透明的,git blame将指向重构提交。

我发现了同样的问题,适用于diff。没有提到任何现有的非专有实现,但提到了一种跟踪块移动的算法

不可能避免这种额外的努力,但Git应该是这样工作的:

另一个基本上明智的设计决策是Git如何进行合并。合并算法很聪明,但它们并不试图太聪明。明确的决定是自动做出的,但当有疑问时由用户决定。这是应该的。你没有想要一台机器为你做这些决定。你永远不会想要它。这是Git合并方法的基本见解:其他所有版本控制系统都在努力变得更智能,Git快乐地自我描述为"愚蠢的内容经理"更好。

(来自Wincent Colaiuta的博客)

不幸的是,据我所知,您无法替换内置的git合并策略。这意味着你无法阻止冲突,但你可以使用智能工具来解决它们。

这个语义合并看起来很有趣,它也可以被git 使用

相关内容