git,在保留历史记录的同时移动/重命名文件的可靠方法



我知道有"很多"现有的问题看起来很相似,所以让我在问我的问题之前总结一下。

  • 是否可以在 git 中移动/重命名文件并维护其历史记录的答案是,"这是不可能的"。
  • 在保留历史记录的同时移动 git 文件的结论是,Git 可能会将其视为移动,或者它仍然可能将其视为删除 + 添加。

第一个问题的答案,我不同意,因为我以前做过。 第二个问题的答案是我问这个问题的原因。即,

我发现我一直在做git mv,但有时它被视为移动/重命名,有时它被视为删除+添加。因此,我想知道如何使其始终移动/重命名?

以这个为例,在底部,我们可以看到几个移动/重命名案例,例如 easygenapi/tf-varcaser.go → tf-varcaser.go .请注意,此类移动是跨文件夹/文件夹之间的!也就是说,我做到了

但是还有许多其他情况git mv被视为删除 + 添加,显示在完全相同的更改日志中。同样,我一直在做git mv。为什么git行为不同?

是否有任何可靠的方法可以在保留历史记录的同时移动/重命名 git 文件?

tl;dr; no

更长版本:根据我的经验,只要文件未修改,git 就非常擅长检测移动/重命名。Git 使用启发式方法来尝试和定位移动。如果有多个文件过于相似,或者文件在移动过程中被修改,导致其与原始文件太不同,则可能会愚弄它。

我发现这样做的最好方法是进行多阶段提交,将所有移动分离到一个提交中,然后在另一个提交中进行更改。例如。。。

git mv foo.txt bar.txt
git commit
... modify bar.txt ...
git add bar.txt
git commit

不能保证正确检测到您的移动,因为当有多个候选人时,它仍然会感到困惑。然而,它对我来说效果很好,并且抓住了大多数情况。

Git 不跟踪重命名。时期。它也不会跟踪添加。或删除。或差异。或补丁。或移动。或者任何形式的改变,真的。

Git 是基于快照的。每次提交都会记录整个项目的快照。就是这样。那张快照是怎么来的,Git 既不知道也不关心。

差异、补丁、添加、删除、移动、重命名等由各种可视化工具显示,这些工具在事后使用启发式方法推断它们(这是"猜测"的另一种说法)。有时,他们可能会猜对你做了什么,有时他们不会。不过,这并不重要,因为它只是可视化,它不是历史的一部分,它以任何方式,形状或形式。

大多数工具使用某种形式的相似性度量,并推断如果两个文件的相似性大于某个阈值,则会发生重命名。在某些工具中,此阈值是可配置的。在某些工具中,甚至算法也是可配置的。(一个稍微相关的示例:git diff允许您在不同的算法之间进行选择,以推断文件中的差异

由于 Git 不记录更改,因此可以在更高版本的可视化工具中添加新的更改,这些更改可以从在编写理解新类型更改的新工具之前记录的旧提交中推断出这些更改。例如,想象一个工具可以理解你正在使用的编程语言的语法和语义。它可以将某个提交可视化为不是一大堆文件,每个文件都有几行更改,而是作为重命名子例程并更新每个调用站点的单个更改(即重命名方法重构)。

重命名实际上就是一个很好的例子。例如,git log --follow使用的重命名检测启发式和相似性指标被多次改进。IIRC,一开始,根本没有推断出重命名,该功能是后来添加的。如果 Git 记录更改而不是快照,这根本不可能。

最新更新