有没有办法将git文件历史记录移到另一个文件中



我正在对我的仓库进行更改。

所以我有文件index.d.ts,我想把它的所有内容移动到另一个文件file1.d.ts,我想将所有index.d.ts提交历史记录移动到新文件。但我仍然不想从存储库中删除"index.d.ts"。

我尝试使用git mv index.d.ts file1.d.ts,但一旦用新内容重新创建index.d.ts,历史记录就会自动移回index.d.ts并从file1.d.ts中删除

有没有办法将当前的index.d.ts文件历史记录移动到文件file1.d.ts

当您想查看文件重命名后的历史记录时,可以使用

git log --follow <filename>

它将通过重命名提交不断向您提供文件的历史记录,一直到文件最初使用其原始名称创建时。

所以使用

git mv index.d.ts file1.d.ts

提交结果,然后当您想查看历史记录时,使用

git log --follow file1.d.ts

理想情况下,只使用git mv操作进行提交,然后在重命名文件后对要在文件中进行的更改进行单独提交。如果对文件进行了一些更改,--follow仍然可以找到重命名,但如果更改过多,它可能无法识别出这是一个重命名,而不是一个无关的新文件。

EDIT在torek的回答中,他们指出了一个重要的细节:如果您想在拥有git mv'后将不同的index.d.ts文件重新添加到您的repo中,请将其作为git mv的单独提交添加回来,否则您将破坏--follow检测重命名操作的能力。他们回答中的细节。

请参阅joanis的答案以获得一个实用的解决方案:重命名文件,提交,然后添加一个,单独的提交,在其中添加一个使用旧名称的新文件。这使得git log --follow能够跟随重命名。

如何理解以及为什么这样做

你问过";将历史移动到另一个文件";,但是Git没有";文件历史记录";首先。Git有提交。提交历史记录。

在Git中,每次提交都会保存每个文件的完整快照。(每个提交也包含一些元数据,但对于这个答案,我们只关注快照。)中的文件这些快照被压缩、Git化并一直冻结,而且——这很重要——要消除其内容的重复。重复数据消除意味着,如果一行中有任何一对提交,Git会调用这些"提交";"父";以及";"孩子";承诺,但暂时考虑一下,就把它们想象成";在";以及";在"之后;,或";旧的";以及";新的"--并且在提交中,有一些文件读取";我是一个文件";,在新的提交中,有一个文件——任何名称——读取";我是一个文件";,这两个文件是彼此的重复,并且是消除重复的

Git可以非常轻松地找到一个消除重复的文件。Git可以找到类似的文件(不完全相同,但基本相同的文件),但这比找到匹配的文件要困难得多,因为它们已经被消除了重复。Git使用这种重复数据消除的主要目的是,当您进行新的提交时,您可能只更改了旧提交中的几十个、数百个、数百万个文件中的一个或两个。因此,新提交中的几乎所有文件都是旧提交中旧文件的副本。通过消除内容的重复,Git节省了大量空间:只有真正必须保存任何修改过的文件,即使两者都提交了"包含";所有文件。

现在,正如我上面所说的,存储库中的历史无非是存储库中提交。当您运行git log时,Git会找到当前提交——通常是您通过运行git checkout mybranchgit switch mybranch选择的某个分支上的最新提交——然后向后工作,一次一个提交,向您显示每个提交的日志消息。这是因为提交历史:如果我们从最后一个开始并显示其日志消息,然后跳回到其父级并显示日志消息,再跳回到一个并显示该日志信息,然后。。。好吧,重复一遍,直到我们用完提交:我们现在已经看到了历史1

不过,有时我们想知道:在哪些提交中,我更改了文件F所以不仅仅是:

git log

我们运行:

git log -- F

如果F,也是分支名称,这里需要双连字符,例如,告诉git log,我们指的是fileF,而不是分支F;当F没有被错误解释时,我们可以省略--,但每次都包含它是个好主意。

这个仍然遍历所有2提交,向后,一次一个提交。但这一次Git使用了";文件完全相同-内容被消除重复";事情假设在当前提交中,文件F存在,并且与上一次(父级)提交中的文件完全相同。Git可以加载两次提交的快照,立即看到文件被消除了重复,并且不需要打印出任何关于当前提交的

Git然后向后移动一跳到上一次提交。Git找到它的父级,加载两个快照,并检查文件是相同的(已消除重复)还是不同的(未消除重复)。如果是一样的话,Git不会提到这个提交。如果不同的话,Git会以通常的方式提到这个提交。

然后,我们永远一次重复一次提交,检查这次提交和上一次提交是否都有相同版本的文件(或者都完全省略了文件)。如果是这样的话,提交是不感兴趣的,Git不会打印它。如果不是——如果文件由于这个提交而发生了更改、存在或删除——那么这个提交是有趣的Git会打印它。

这样做的最终结果是;参见";a";文件F"的历史;。但文件F没有历史记录:只有提交,这些就是历史记录。我们所看到的不是";F"的历史;是";所有历史,除了F没有改变的提交";。是同一件事吗?好吧,也许:输入--follow

假设我们处于某对提交<CCD_ 27、CCD_;。Git将提取这两个快照,并查看名为F的文件是否同时存在,或者两者都不存在。进一步假设F存在于new中,而不存在于old中。由于--follow,Git现在可以查找old中存在new中不存在的文件。假设有五个这样的文件。这些是我们的候选文件。我们现在检查这五个文件中是否有任何一个是";足够相似";到new中的副本。

这张支票对";"完全相同";,所以我们让Git先检查一下。如果这五个文件中的任何一个是100%相同的,因此被消除了重复,那么为什么old中名称为oldF的文件在new中必须被重命名为。因此:

  • git log打印提交new,因为文件发生了更改(无论如何都会这样做),
  • git log --follow更改它要查找的名称。它不再查找文件F,现在正在查找旧的F

如果100%相同的东西不起作用,git log使用较慢的";它足够近吗;火柴您可以设置匹配阈值:默认情况下需要至少50%的匹配。如果超过一个文件满足阈值,Git将采用最高匹配文件,并将其称为";旧文件";名称如果没有文件达到阈值,Git将假设文件F已被删除,并继续查找名称F,看看它是否在早期提交中被重新创建。

为了实现这一切,旧文件名必须在某对提交之间消失,并且您必须使用出现在同一新旧提交对中的文件名启动git log --follow。提交仅重命名操作将确保(a)发生这种情况,并且(b)匹配是100%匹配,因此进行得很快。因此,将文件commit重命名为单独的commit可以使git log --follow工作得很好。

(不过,git log --follow中存在缺陷。请参阅脚注2,并注意,目前实现的--follow只能处理一个文件名。您必须知道新的名称:--follow不适用于git log --reverse。)


1更准确地说,我们已经看到了可到达的提交,从当前提交开始并向后工作。有关可达性(这是Git中的另一个关键概念)的更多信息,请参阅Think Like(a)Git。

2这并不完全正确:git log -- <path>打开git log所称的历史简化。这使得Git丢弃某些历史路径。当使用--follow时,这比看起来损失更小。有关这方面的(更多)信息,请参阅,例如,git log没有正确返回文件的历史记录,git log(--follow)无法显示重命名之外的历史记录以及其他提到历史简化的答案。

相关内容

最新更新