缺少文件历史记录中的行删除(git)

时间:2018-01-17 06:02:34

标签: git

我们正在使用git进行源代码控制。

如果我查看特定的文件历史记录(使用git log --pretty=format:"%h %ad" --date=short <filename>),我会看到类似的内容:

HashOfCommitA 2018-01-15
HashOfCommitB 2018-01-09
HashOfCommitC 2018-01-05
<older commits>

CommitA和CommitB是合并提交。

在CommitB(git diff HashOfCommitB <filename>)的更改中,有两个新行添加到文件中。 在CommitA的更改中,这些行没有受到影响,但是如果我在CommitA合并之后检查文件内容,那么在CommitB中添加的两个新行将丢失。

基本上,当我查看文件历史记录时,我可以在某一点上看到添加了某些内容,但在下一次提交后,它已丢失,我在提交时看不到删除这些行变化。

可能是因为合并是使用旧版本的分支(没有CommitB)?如何找到这些行被删除的位置?

换句话说,怎么可能?有没有很好的方法来防止将来出现这种情况?

1 个答案:

答案 0 :(得分:1)

相关:Git; code disappeared after merge。特别注意表现不佳的工具,这样可以很容易地只保留一个&#34; side&#34;没有思考的合并冲突作为一般规则,避免问题的一种好的,可靠的方法是在接受之前对每次提交进行彻底的测试。

  

如果我查看特定的文件历史记录......

这里要小心。 Git没有拥有文件历史记录;您所看到的是由Git选择特定提交而产生的假伪历史 - 提交 历史记录,而完整的提交集是实际存储库中唯一的历史记录 - 作者git log认为是一个很好的过滤选择。当您使用此类过滤时,默认情况下,git log会启用它所称的历史简化,这在this section of the documentation中有所描述(在我看来相当糟糕)。我发现这可能会产生误导。

除此之外,除非您使用--graph,否则git log的输出将被排序和显示,这使得很难或有时无法确定哪些提交确实发生在哪些点上。这里存在一个基本问题,即以线性顺序显示基本上不是线性的:

       B--C
      /    \
...--A      F--G   <-- branch-tip
      \    /
       D--E

这里,提交G显然是最后的,所以Git会先显示给你。接下来会提交F(即G之前),因此Git会向您显示F。但现在Git可以向您显示 <{em> C E。它应该选哪一个?

Git的默认设置是提交时间,因此如果在C之后E稍微发生,Git会在此显示C 。那么接下来可能会发生E,以Git向后的方式(即更早),所以Git现在显示E;现在Git可以显示BD。一旦显示,它可以显示另一个或A,但另一个(BD可能接下来,除非提交是在时间设置错误的情况下进行的,或者是在另一台对正确时间有不同想法的计算机上进行的。

最终,你确实看到了所有的提交 - ,除非,也就是说,历史简化已经删除了一些,也许是整个分支机构。 (即使没有历史简化,它们显示的顺序有时很难预测。)更糟糕的是,在默认的历史简化模式中,上面提到的(可能是难以理解的)文档提到:

  
    

如果提交是合并,并且它是一个父级的TREESAME,则只关注该父级。 (即使有几个TREESAME父母,也只能跟随他们中的一个。)否则,请跟随所有父母。

  

在您的情况下,您将获得默认模式,因此如果合并的作者选择了一个&#34; side&#34;一个分支(故意不从另一方改变),Git完全修剪另一方。但是,这正是您认为应该保留的变更的确切位置,因此git log实际上对您撒谎了!

我也会加上这个,虽然这可能只是略微相关:

  

CommitA和CommitB是合并提交。

(这意味着这些是至少有两个父母的提交,可能只有两个父母。)

  

在CommitB的更改中(git diff HashOfCommitB <filename>)...

如果您以这种方式运行该命令,那么您要求Git将合并中存储的内容(合并结果)与当前工作树中的内容进行比较。这是the description section of the git diff documentationgit diff的第四种形式。因此,这些不是存储在合并提交中的更改

实际上,合并提交中没有存储实际的更改。以这种方式,合并提交就像任何其他提交一样:它存储快照,在Git&#34;眼睛&#34;无论如何 - 只是合并的正确结果(正如运行git merge的任何人告诉Git一样,正确性的证据是任何运行git merge的人都提交了结果)。该合并有多个输入 - 通常是(两个)父项加上它们(单个)合并基础 - 您可以将最终合并快照与两个父项中的任何一个进行比较,从而查找更改,但更改您发现父母#1与父母#2相关的更改不同。