合并后Git提交丢失

时间:2016-09-13 09:22:22

标签: git

我们有3个分支(A,B,C)如下:

---\--A1--\------Am------Merge1---An---Merge2---
    \      \              /             /
     \      \--C1---C2---/             /
      \                               /
       \--B1--------------Bn---------/

问题出现在Merge2上。在Merge1和Merge2之间的Merge2之后的分支A上,分支C上的一些提交(不是全部而是一些,让我们说C2)丢失了。

执行Merge2时,只有一个文件冲突,与丢失的提交(C2)无关。我们解决了这个问题并成功完成了合并。

似乎C2在分支A上被Merge2反转,没有任何记录。

发生什么事了?这种情况可能是什么原因?

2 个答案:

答案 0 :(得分:16)

你的意思不是提交本身丢失了,而是该提交中的更改(到某个文件)已被还原(未提取) )。

值得注意的是,承诺并未真正改变"文件。相反,每个提交都存储一整套完整且完整的文件。当你要求Git向你展示一些提交时(让我们说它的ID为c2c2c2...):

$ git show c2c2c2

Git的作用是:

  1. extract commit c2c2c2...
  2. 提取c2c2c2...
  3. 的父提交
  4. 生成从父级到子级的差异列表
  5. 这就是Git如何设法向您展示改变的内容:它比较了您在提交之前所拥有的内容"到了#34;你所拥有的那份承诺"。 (Git可以非常快速地进行优化,因为每个文件都被简化为一个独特的哈希"指纹",Git可以先比较指纹(哈希)。如果哈希是相同的,那么文件是相同的。如果哈希值不同,它只需要提取实际的文件数据。)

    这个节省流程的整个文件,而不是累积更改,被称为"存储快照"。 (其他版本控制系统倾向于累积更改,称为"存储增量"。他们这样做是因为将更改保存到文件显然比保存文件所占用的空间要少得多。无论如何,以一种聪明的方式绕过这个问题,并且使用比旧的基于delta的版本控制系统更少的磁盘空间。)

    为什么" Git存储快照,而不是增量"在这里很重要

    合并提交是特殊的,以一种特别明显的方式。查看您自己的图表并考虑Merge1。什么提交才出现在它之前?

    这里的答案是AmC2来到"之前" Merge1。也就是说,提交Merge1具有两个父提交。

    如果您要求Git向您显示提交Merge1,哪个父级应与之进行比较?

    这里的事情变得特别奇怪。两个命令git log -pgit show 似乎非常相似。事实上,他们 非常相似。一个明显的区别是git log -p显示多个提交,而git show只显示您告诉它显示的一个提交。您可以运行git log -n 1 -p <commit>来显示一次提交,现在似乎就像完全一样。

    他们不是!

    当你在合并提交中使用git show时,Git会尝试解决&#34;什么提交要比较&#34;通过同时比较两个父母的问题。生成的差异称为组合差异

    当你在合并提交中使用git log -p时,Git只是抛出了它的隐喻之手,并说#34;我无法显示针对两个父母的补丁&#34;,并放弃了继续下一次提交。 换句话说,git log -p甚至无法为合并尝试差异。

    但等等,还有

    现在,在这种情况下,您可能想知道是否可以使用c2c2c2...在两个合并上提交git show提交文件的内容,特别是在{{1}上},其中的变化被还原。但是Merge2默认情况下会产生组合差异,并且组合差异会故意省略很多差异输出。特别是,组合差异lists only files which were modified from all parents

    让我们说明您的git show更改所依据的文件是文件C2。而且,从图表中,f2的两个父母Merge2An的方式是{}}和f2({1}}({1}}。

    这里实际发生的是,在创建Bn的合并期间,您以某种方式告诉Git使用来自提交Merge2的{​​{1}}版本。也就是说,f2中的文件Bnf2中的文件Merge2完全相同,并且与提交f2中的Bn不同。< / p>

    如果您使用f2来查看An,则合并后的差异将跳过 git show,因为它与相同 Merge2中的f2

    同样如此,更糟糕的是,使用f2:它完全跳过合并,因为它太难以显示差异。

    即使没有Bn,当您要求&#34;文件已更改&#34;时,git log -p也会做同样的事情 - 完全跳过合并。这就是为什么你无法在日志输出中看到它。

    (另外,-p从不显示提交git log本身的原因是为git log master -- f2的选项添加文件名会启用&#34;历史记录简化&#34;在我认为有些错误的行为中,Git最终简化了太多历史记录,因此它永远不会显示提交C2。在{{1}之前添加git logC2恢复到显示的提交集。但是,合并仍然缺失,因为--full-history会跳过它。)

    如何查看更改

    有一个解决方案。 -- f2C2都会使用另一个标记git log,其中&#34;分割&#34;合并。也就是说,不是将git show视为合并提交,而是将合并分解为两个&#34;虚拟提交&#34;。一个将是&#34; git log vs -m&#34;,您将看到这两个提交之间的所有差异,另一个将是&#34; Merge2 vs Merge2&#34;,您将看到那些两次提交之间的所有差异。这将显示文件An已重新设置为Merge2中的格式,从而Bn中显示f2Bn中未显示的版本}。

    (包括C2以及An以确保提交Bn也会显示。)

    首先发生了这种情况

    此部分清楚。你说有一个合并冲突,这意味着--full-history停止并获得人工的手动帮助。在此辅助期间的某个时刻,人员可能使用-m中的文件C2的版本更新了索引(或者至少是没有进行更改的git merge版本)在f2)。

    这可能在合并期间发生,并且它有点隐蔽,因为 Git显示与这些压缩(组合)差异的合并,或者在Bn的情况下,而不是所有,默认情况下。需要注意的是,特别是如果合并需要手动解决冲突。在大多数情况下,捕获此类合并错误的方法是使用自动化测试。 (当然,并非所有东西都可以测试。)

答案 1 :(得分:0)

我也遇到了这个问题,这是我的解决方法:

  1. 使用git log来显示我的提交历史记录。

  2. 使用git show <filename>来显示对顽固文件的更改。

  3. 不起作用。搜索StackOverflow,尝试了几次。

  4. 关闭并重新打开文件。瞧!

在Atom文本编辑器中新打开的文件显示了我期望的更改。