如何在git中执行“ hg mv --after”?

mar*_*ark 2 git

我在git之外重命名了一些文件,并对它们进行了重大修改。当我运行时, git diff-index -M --name-status HEAD我只能看到4个文件被重命名/移动,而应该更多。

我知道我可以使用在Mercurial中记录移动后的情况hg mv --after。我找不到git中的等效项。在那儿?

tor*_*rek 6

正如Dietrich Epp 已经回答的那样,您不仅不必这样做,而且从字面上讲也可以。从评论中可以看出,您仍在为这个概念而苦苦挣扎。回顾一下通用的版本控制系统(VCS)理论可能会有所帮助。

像许多(大多数?)其他VCS一样,Mercurial也具有很强的文件身份概念。这就是为什么必须使用的原因hg mv,如果忘记了使用,请使用hg mv --after:Mercurial知道某个路径的文件是在某些commit C n中首先引入的,从那时起,通过以下方式跟踪该文件的身份记录任何重命名操作。

其他VCS通过其他机制执行相同的操作,例如将路径名映射到对象标识符(类Unix的“ inode号”或ClearCase“ OID”)。文件的历史记录以某种方式附加到此对象ID。尽管Mercurial不使用数字OID / inode-number,但通过记录重命名(以及复制和删除)来跟踪清单中文件的技巧也得到了相同的结果。

Git抛弃了整个概念。Linus宣布您不需要它,因此他根本就不会这样做。在任何提交中,文件都没有其存在或不存在的任何标识。文件foo在提交ç 0是完全无关的文件foo在提交Ç ñ(其中ň?0)......除非,事后,您(或GIT)决定,这应该是相关的。(请参阅下面的旁注。)

如果git diff文件名称相同和/或足够相似,则该命令确定两个不同提交中的两个文件相关。否则它们是无关的。它决定这对飞,在运行时git diff,根据您传递给选项git diff。因此,如果git diff使用不同的选项运行两次,则会得到不同的答案。文件f1f2可能涉及(重新命名或复制)或相关(f1删除,f2创建)。

如果您对VCS非常熟悉,您将立即提出反对:是否会干扰增量压缩? 答案是肯定的,但是的确如此,但是Git不执行增量压缩。

(等等,什么?!?)

好吧,让我们稍作调整。Git不会做增量压缩尚未

在存储库中的“松散对象”级别,Git根本不执行增量压缩。它只是将文件内容减少为单个哈希值,并声明所有哈希为相同值的文件都是同一文件。内容的哈希内容的标识(名称)。因此,如果f1提交C 0在内容方面与f2提交C n相同,则该内容仅存储一次,作为由其哈希命名的对象(即使n = 0!)。

后来,Git会使得“包文件”并不会做增量压缩,但它通过挑选自认为意志增量压缩以及分组时,其他对象这样做。在这个对象选择中有很多毛发和魔力,而Git实际上偷偷看了文件名就可以做到这一点,但至少在原则上,它只是在整个历史记录中对整个存储库挥舞着魔杖,并说:“啊! ,如果我blah从提交9999999和内部树对象中对文件进行delta压缩,然后以链式1234567提交abcdef2在一起,那么我会得到很好的结果,所以我会做到这一点!”

旁注:文件历史记录

其结果之一是,在Git中,文件实际上没有历史记录。由于没有真正的文件身份概念,因此您具有提交历史记录,但没有文件历史记录。但是,Git会通过将每个提交与某些先前的提交进行比较,并有时甚至声明两个具有不同路径名的文件相互关联来为您合成历史记录。git log --follow例如,使用这样做。但这通常是一件很难的事情,而且git log --follow做起来相对较差:您可以通过一个提交链跟踪一个路径名,一次跟踪一次提交,然后尝试发现重命名。该代码仅在从较新的提交到较旧的提交时才有效,因此您不能git log --follow --reverse where/did/this/get/renamed/to。也就是说,如果你知道有一个带有某些路径名的文件,并且想知道它是否仍然存在,Git不太擅长告诉。(本质上,您需要git log --raw搜索R原始名称的状态。如果找到这样的状态,则可能需要重复使用新名称,直到找到以“我知道的文件”开头的每个重命名然后将其转换为“今天看来与内容相关的文件”。)