在Git中删除之前查看还原文件的历史记录

时间:2019-02-24 22:44:01

标签: git

我有一个文件foo.bar,它具有多年的悠久而有趣的历史。已被修改。它已被重命名。使用正确的git log参数,我仍然可以跟踪其修改历史记录。这对我很重要。

在修订版33333中,我删除了foo.bar,因为似乎我们需要该功能。但是后来有四次提交,在修订版77777中,事实证明我们需要该功能,所以我想返回foo.bar

大多数人都知道我可以发出:

git checkout 3333 -- path/to/foo.bar

但是似乎没有人确切地知道我是否仍会看到发行git log,修订版88888及以后的完整历史。

例如,

https://stackoverflow.com/a/42287548/421049声称回答了这个完全相同的问题。 但是,关于删除前后的历史记录是否会记录在日志中的答案尚不清楚,并且注释中的问题也没有得到解答。

2 个答案:

答案 0 :(得分:3)

找出答案的方法就是尝试一下。

如果您尝试,您会发现git log -- file(有或没有--follow的确确实在寻找。

注意:

  

使用正确的git log参数,我仍然可以跟踪[特定文件的]修改历史记录...

请务必记住,Git不存储文件历史记录。 Git存储 commits ,并且这些commits及其图形是历史记录。

当您运行git log -- filegit log --follow -- file时,Git通过显示实际历史记录的某些选定子集来合成文件历史记录。当然,实际的历史记录是每次提交都从某个结束点开始并向后进行,直到所有合并的父级之后,除非--first-parent仅用于跟随合并的第一个父级。 / p>

通过省略一些提交并显示其他提交而产生的有限的综合历史记录当然取决于所显示的提交和省略的提交。在这里,区分两个独立的过程变得很重要:

  • Git如何确定要遍历的提交?
  • 遍历了这些提交,Git如何决定要显示哪些提交?

无限的默认git log操作是遍历所有reachable提交并显示遍历所有提交,这使两个问题成为同义词。您只需要了解 reachability 的概念,这就是我在此处提供指向Think Like (a) Git的链接的原因。但是,一旦启用the git log documentation calls History Simplification,则两者将分开。该文档使用了我认为较差的措辞:

  
    

一部分是选择提交,另一部分是如何执行

  

这里的意思是:

  • 一个部分是选择要显示的提交 (添加我的,强调我的):这是我的第二点。在从起点开始遍历提交的某些子集之后或期间,我们显示了那些提交的某些子集

  • 另一种方法是[遍历]:“ it”在这里是一个特别没用的代词,指的是简化历史的一般思想。这等于说用于简化历史记录的方法就是用于简化历史记录的方法,那...好吧!

无论如何,主要思想(从--ancestry-path选项开始适用于所有事物)是从这里称为TREESAME的概念开始的。要应用该想法,我们还必须查看每个提交的父母。

当然,我们已经知道要进行任何类型的提交图遍历,我们让Git从对象数据库中抓取一个提交并对其进行检查并收集其父哈希ID。大多数提交只有一个父母,因此很明显下一步应该去哪里。一些提交(至少有一个提交)是 root 提交,它被定义为具有 no 父母的提交,很明显,在这里也可以做什么:停止遍历。其余的提交(既不是root也不是普通的)都是 merge 提交,默认情况下,在不简化历史记录的情况下,Git会查看每个合并提交的 all 个父级。

但是,启用历史记录简化后,Git 不会查看所有父母。相反,它使用此TREESAME想法。为了确定提交C(子级)和P i (第i个父级)是否为TREESAME,Git会比较该提交中我们感兴趣的所有文件的内容-现在--follow和/或-- path部分很重要,因为这声明了我们现在发现哪些文件有趣。因此,Git假装提交C和P i 的人中只有个文件,并说:文件是相同还是不同?

如果文件不同,则两次提交不是TREESAME。如果文件内容相同,则两次提交为TREESAME。

如果它不是对任何父代的TREESAME,也就是说,如果C中的文件经过剥离,Git将选择提交C以显示。不同于任何P i 。但是,如果提交是合并提交(有一个以上的父项),则默认情况下,它将跟随的父目录会找到更多可能显示-可能遵循的提交,这是该父目录之一, em>是C到TREESAME。

有一些选项(共有五个选项,包括默认选项)可以更改提交跟踪的工作方式。其中的一个--sparse也会更改要显示的提交集,否则,此“非-TREESAME到任何父母”规则是用于显示遍历提交的规则。

最后,我们可以看看--follow本身。这很简单-可能很简单,例如,由于失败--full-history而已。与任何git log -- paths操作一样,它打开了历史记录简化功能,因此仅提交“触摸”给定路径的提交才会显示。但是,它还启用了Git的重命名检测,同时要求仅指定一个 path

当Git遍历从子对象到父对象的提交时,执行简化步骤来确定(a)要跟随的父对象和(b)要显示的父对象,Git还会检查与父对象之间的差异- to-child,表示子目录中 path 处的文件是父目录中不同路径重命名的结果。如果是这样,那么只要Git从检查提交C切换到检查父提交P,它就会 切换用于简化历史记录的路径名。现在,例如,可能正在寻找path/to/file.ext而不是old/path/to/file.txt

如果您的提交图中有提交,而在path/to/file.ext等路径下没有文件的没有副本,则git log仍会遍历这些提交。只是那些提交显然不更改该文件-它们甚至都没有该文件-因此,每个子提交对于其每个父提交都是TREESAME。在遍历的某个时刻,如果出现path/to/file.ext 在父母而不是孩子中的提交,则遍历可能(也可能不会)(取决于您选择的历史记录的简化形式)搬到那个父母那里。如果在普通的单亲提交中添加或删除文件,则该行为很容易理解,因为没有特殊的TREESAME怪异应用。如果在作为合并的提交C中添加或删除了文件,并且该文件具有多个父P 1 …P n ,则TREESAME规则默认情况下会将Git删除没有没有文件的提交图路径!

要真正弄清楚这一切,请研究the git log documentation。答案就在其中-无论如何,一旦您可以克服不太好的措辞。

旁注:git blame不同

git loggit blame都将遍历提交图,但是git blame(或其收费较低的同义词,git annotate)中的算法却截然不同。要查看哪些提交的文件。它的目标是找到哪个最近的提交更改了任何给定文件的任何给定行。当您到达父提交中不存在文件但子文件中存在文件的位置时,会添加每行,因此树遍历就此停止。

要在此之前继续操作,有必要找到一些早已包含该文件的提交-使用git log,简化历史记录和不< / em>以提交为起点。然后,您可以在文件存在的位置开始git blame操作,然后从该位置向后进行操作。

答案 1 :(得分:0)

是的,历史记录已保存。

评论中的问题是关于git blame foo.bar,而不是关于git log foo.bar