将文件名重命名为旧名称会丢失Git中的历史记录

时间:2018-08-10 20:41:54

标签: git

我的git仓库中有两个文件。

  • Editor.cs
  • Editor2.cs

第一个文件是该类的较旧版本,在确定新版本(Editor2.cs)正常工作之前,我一直使用该文件。

现在,我想删除 Editor.cs ,并将 Editor2.cs 重命名为 Editor.cs 。但是,当我在git中执行此操作时(即在Editor.cs上执行 git rm ,然后在Editor2.cs上执行 git mv 到Editor.cs),我似乎失去了Editor2.cs的历史记录。

也就是说,当我查看(新重命名的)Editor.cs的日志时,它向我显示了原始 Editor.cs(而不是Editor2.cs)的历史记录。

我尝试使用 git log --follow ,它仍然显示错误文件的历史记录。

对不起,如果这令人困惑...

谢谢

1 个答案:

答案 0 :(得分:2)

如果您想git log --follow跟踪文件,则可以做一些事情。但是,它与使用git mv无关。我将描述Git的工作原理,然后您可以决定要执行的操作。

事实上,按照您的建议,Git不会丢失文件的历史记录。 Git 确实失去了通过git log --follow 跟随该历史记录的能力。这种看似矛盾的状态是因为Git 从来没有任何文件历史。

Git所拥有的-存储在资源库中的内容-是一系列 commits 。每次提交都是所有文件的完整快照(截至该提交)。当您运行git log(无--follow)时,Git会以某种顺序一次向您显示这些提交。如果顺序基于提交的时间,则 1 会显示历史记录或历史记录的至少一部分。但这就是 commits 的历史,而不是文件的历史。

使用git log --follow告诉Git:保留一些提交。像往常一样浏览提交历史,但是仅告诉我有关提交的内容,即此提交的直接前任与该提交本身之间的差异更改了我命名的一个文件 这不是文件历史记录;这是提交历史的一个子集,基于一个文件的名称。

诀窍在于,使用--follow时,Git将自动切换从寻找名为new.txt的文件到名为{{1 }},是否以及何时某些提交中的更改是重命名。但是,可以以某种特殊的方式启用此特殊技巧。 Git使用重命名检测,在其中比较两个提交并尝试猜测(而不是记住)是否在这些提交中重命名了某些文件。 2

为了将父提交与子提交(连续进行的两次提交)进行比较,Git提取(实际上是提取)这两个提交中的每一个。然后,它将查看两次提交中每个提交的所有文件 names 。在旧提交中名为old.txt的文件会自动假定与新提交中的read.me是“相同”文件。但是,如果旧提交有一个read.me而新提交没有,而新提交有old.txt而旧提交没有此文件,则 then 至少要重命名检测-Git将查看两个文件的内容。如果new.txt中的内容与old.txt中的内容足够相似,则 3 Git决定将这些文件设为“相同”文件,因此new.txt被重命名到old.txt

Git不在这里查看文件的名称,而是在数据上。 4 因此它不会检测到new.txt类似于Editor.cs,除非内容确实非常相似。但更重要的是,如果有一个提交(父文件)仅用一个文件名中的一个 ,则只会比较两个文件的内容立即通过仅包含其中一个文件(用其他名称)的第二次提交(子)。如果一个提交有两个文件,而另一个提交有一个文件,则Git只会说该文件已添加(父项缺少+子项拥有)或已删除(父项拥有+子项不足)。

因此,要检测到此文件为“相同文件但名称不同”,您将需要进行一次提交,其中只有一个个文件,然后执行更新的提交,其中仅包含这些文件中的另一个。这两个文件的内容也必须足够相似。 “完全相同”是最好的-找到100%相同的匹配要比匹配次要的匹配快得多-并且在这里使用Editor2.cs可以保证您进行的提交具有更改后名称的100%匹配文件, git mv可以检测到。但是关键是要一次删除所有旧名称,然后显示新名称。对于您而言,这意味着您需要删除新文件,提交,然后:

  • 重命名旧文件并再次提交(匹配100%),然后用新内容替换旧文件内容(否名称更改= Git认为文件相同),或者

  • 删除旧文件并创建新文件并提交,以便存在可检测的重命名,只有当内容的相似性等于或大于50%时,才会真正检测到该重命名

执行上述任一操作都将导致git log --follow检测到从新名称到旧名称的重命名,然后git log --follow将开始寻找 old 名称,并且禁止不修改名称为 old 的文件的提交。


1 默认情况下,订单提交的顺序几乎是,但不完全是。实际上非常复杂。添加git log --follow会强制执行严格的拓扑正确顺序,尽管可以进行分支和合并,但某些提交将没有祖先/后代关系。

2 进行这样的重命名检测的一个优点是,当比较不紧邻的提交(例如进行合并)时,Git可以检测到重命名。缺点很明显:很难!记录“文件X被重命名”会容易得多。其他版本控制系统可以做到这一点。

3 默认值是使用计算出的相似度索引要求文件“相似度为50%”。使用--topo-order时可以进行调整。使用git diff时,您只会得到50%的数字。

4 如果文件的路径名具有相同的最终组成部分,则相似性索引将提高1%。也就是说,git log --followdir/sub/file.txt的相似度为49%,与dir2/sub2/xyz.txt的相似度为49%,但是后者具有相同的dir2/sub2/file.txt最终成分,因此将其提升为神奇的50%标记。