提交记录显示在历史记录中,但更改不在文件中,并且在单个文件提交历史记录中也不显示。

15
我在使用git时遇到了一个非常奇怪的问题,昨天我提交了一个commit,此后其他几个人也进行了提交。现在我在github上看到我的这个commit在历史记录中,但是我所做的更改并未出现在文件的HEAD修订版本中,而且如果我查看单个文件的历史记录,我的commit也不会显示出来。我的队友告诉我他们所做的都是常规的pull和push,文件也没有冲突。如果有人使用了force push,我就会期望我的commit完全消失。如果有人搞砸了合并冲突解决,我就会期望合并commit会撤销我的更改,并在文件的commit历史记录中反映出来。但不知何故两者都不是。简化一下:
  • 我更改file.txt并创建commit ABCD
  • 我将ABCD推送到github上
  • 其他人推送了其他提交,没有影响到file.txt
  • 如果我在github上查看存储库提交,我可以看到我的commit,也可以查看更改差异
  • 如果我在github上查看file.txt的最新版本,我的更改不在其中
  • 如果我查看file.txt的提交历史记录,ABCD不会出现,该文件的最后一个提交是ABCD之前的提交。

为什么会发生这样的情况?

编辑:根据评论中的讨论,这是我的提交图中的一部分:

* | 8c1d372 ...
* |   98dbad7 合并分支 'master'
|\ \  
| * | 8d64a09 ...
| * | 12beb68 ...
| * |   1c94b6d 合并分支 'master'
| |\ \  
| | * | 80b6285 ...
| | * | 9781fad ... (我的commit)
| | * | f12fc90 ...
| | * | 61411fa ...
| | * | 291333b ...
| * | | aeee93f ...
| |/ /  
| * |   bcfbf65 合并分支 'master'

我的消失的commit是9781fad。如果我checkout到8c1d372,我的更改就会消失。然而,在我的commit之后没有任何commits实际上会影响到我所更改的文件。


你们使用什么样的分支结构? - code4pi
我们目前还没有采用Git Flow。最近我们只有一个开发人员在处理这个代码,所以目前所有的更改都会提交到主分支。我们正在考虑使用Git Flow。 - Mad Wombat
3个回答

14

实际答案(而不是超长的评论)。

这里再次呈现图形部分,以及我自己的注释:

* | 8c1d372 ...        <-- lacks desired changes
* |   98dbad7 Merge branch 'master'     <-- ? (interesting #1)
|\ \  
| * | 8d64a09 ...
| * | 12beb68 ...
| * |   1c94b6d Merge branch 'master'   <-- ? (interesting #2)
| |\ \  
| | * | 80b6285 ...    <-- probably also has desired changes
| | * | 9781fad ...    <-- is commit that makes desired changes
| | * | f12fc90 ...
| | * | 61411fa ...
| | * | 291333b ...
| * | | aeee93f ...
| |/ /  
| * |   bcfbf65 Merge branch 'master'

由于没有人明确地还原了您的更改,并且它们是针对其他人不应该编辑的文件进行的,因此几乎可以确定,无论谁错过了您的更改,都是通过执行错误的合并来实现的。

有两个合并是有趣的,我已经标记了#1. 提交98dbad7有两个父级:一个我们看不见(在图形底部),一个我们可以看到,即8d64a09。从这个点开始的git log将显示两个历史记录。git show 98dbad7:path/to/file将显示附加到合并提交的文件版本(即合并者指定的那个文件的正确版本)。如果那是错误的版本-如果该文件缺少所需的更改,则合并本身可能出了问题或输入有误。假定那个位于底部之外的父级不应该具有该更改,因此此时我们应该遵循另一个父级,即8d64a09

您可以使用git show 8d64a09:path/to/file查看该版本是否包含或缺少您的更改。如果您的更改在其中,则是98dbad7提交删除了它们。如果您的更改不在其中,则我们应该继续。

为了完整起见,我们可以查看12beb68,但它可能不是罪魁祸首。这是一个普通的提交,只有一个父级1c94b6d

提交1c94b6d是我们第二个有趣的合并。与任何合并一样,它有两个(或更多,但通常是两个)父级。这次我们可以看到两个父级,它们是提交80b6285aeee93f

提交80b6285很可能具有您的更改,因为它是一个普通的提交,其父级9781fad 具有您的更改的提交。提交aeee93f将不会有您的更改,因为它来自于没有您的更改的合并的一侧。:-) 您可以使用git show 80b6285:path/to/file仅仅是检查那个提交者是否暗中(而不是公开)还原了它们,然后使用git show 1c94b6d:path/to/file来观察是这个有趣的合并#2删除了您的更改。

很有可能其中一个合并删除了您的更改。 为什么仍然是一个有趣的问题,但必须由进行该合并的人回答。他们做了某些事情-也许是检出,也许是给予合并的标志,在合并期间删除了您的更改。找出哪个合并删除了更改,并与执行此操作的人交谈以找出他们删除它们的原因。

获取更改

将更改带回来非常容易:只需使用git cherry-pick,它会为您运行差异,然后将该差异应用于当前提交。因此,您需要返回到master,然后简单地使用git cherry-pick 9781fad。它将对


2
看起来98dbad7是合并时删除了我的更改。我已经在单独的提交中重新提交了我的更改,其他受影响的人也这样做了。当我执行git show 98dbad7时,我可以看到我的更改被还原了。仍然让我有点困扰的是,为什么文件的日志不包括合并提交,即使它受到了影响? - Mad Wombat
1
出于同样的原因,“git show”不会显示它:默认情况下,合并过程太嘈杂,不能使用“-m”模式。但是,“log”和“show”都接受“-m”。 - torek
对于你在“获取更改”下进行樱桃挑选的描述点赞 - 也许应该更高一些...或者减少其他大段文字。 - Don Cheadle

3
这篇答案提供了如何找到答案的指导。
使用提交图形查看器(或只是“git log --graph”,通常最好作为“git log --graph --oneline --decorate --all”调用),以查看您特定的提交在Git DAG中的位置。如果图形很线性,那么就很容易跟随。如果它充满了分支和合并操作,那么它将更加棘手,并且很可能是由于某个错误的合并引入了问题。如果它充满了未合并的分支,甚至只有一个未合并的分支,那么也许这就是问题所在。
(使用“--all”将向您显示所有标签,包括所有分支名称,并使用“--decorate”将标签附加到它们指向的提交上。“--oneline”选项仅将日志输出压缩为每个提交一行,适合在文本窗口中放置更多内容。)
使用“git show”查看任何普通(非合并)提交:这会显示提交元数据(作者、时间、日志消息)并运行“git diff”以比较该提交的树与该提交的父级的树。例如,“git show ABCD”应该显示您的更改,因为您提交的树对该文件进行了更改,与您在进行提交“ABCD”之前开始的树进行了比较。
假设您的提交“ABCD”位于您希望它在图形中的位置,再查看后续提交(再次使用“git show”)——后续提交是靠近“HEAD”的提交——以查看谁撤销了您的更改。然后,您可以尝试弄清楚他们是如何做到的,也许通过与他们交谈。
如果后续提交是合并——具有两个或更多父项的提交——“git show”通常不会向您显示太多内容,您需要使用“git show -m”,或手动运行“git diff”,以查看两个比较:从第一个父项到该提交,以及从第二个父项到该提交。“-m”标志告诉“git show”为您执行两个单独的差异。(您可以为非合并提交提供“-m”;它对它们没有任何作用。它不是默认值,因为通常合并会显示大量冗余更改。)
顺便提一下,git log -- path 并没有真正“显示文件历史”,因为Git没有每个文件的历史记录。相反,这个 git logHEAD 开始沿着提交图向后遍历,找到所有可达的提交,但是然后舍弃似乎不影响所询问的文件的提交。目前不清楚您为什么在此处没有看到您的 ABCD 提交,但是日志的图形版本和 git show 输出应该会更清晰地解释原因。
根据下面的评论:当检出标记为 45 的提交时查看 git log 输出的描述(当检出 5 时,我们可以看到 5、4、3、2 和 1,但是当检出 3 时,我们只会看到 3 和 2),至少有一个是合并提交。
假设 4 是唯一的合并提交,则我们可以将此特定的图形片段绘制如下:
... <- 1 <------- 4 <- 5    <-- master
                 /
... <- 2 <- 3 <--

这里的分支(master)指向提交5,这是一个普通的非合并提交,而提交5指向提交4:提交4是合并提交,合并了提交13的内容;它有两个父提交,31(以某种顺序)。提交3是一个非合并提交,其父提交为2。我们对提交12几乎一无所知:我将它们绘制成具有不同父提交的形式,但也许它们有相同的父提交。
提交5可能是合并提交,或者45都是合并提交;我们唯一能确定的是,基于从5执行git log命令时会显示1,而从3执行git log命令时不会显示1,因此1不在3的历史记录中。
请注意,历史记录是通过按箭头指向的方向进行跟踪而发现的,永远不要逆着箭头走。如果我们从5开始,而4是合并提交,它有两个出站箭头,因此我们跟随两个历史记录以获取4的历史记录。
虽然git log --graph将历史记录垂直绘制(并且不放置箭头),但它显示了相同的信息,如果没有--graph,你就看不到这些信息,但这对于未来操作(如依赖当前图形的合并)非常重要。
请注意,如果上述图形片段准确无误(我仍在猜测,因为您尚未发布git log --graph --oneline --decorate --all输出片段),那么我们几乎可以确定发生了什么事情:在4中进行合并的人告诉Git清除了您的更改,取代了提交3中的内容。

感谢您提供了一些我不知道的命令,但是我已经非常彻底地追踪了提交历史记录。我的提交在历史记录中。其中的更改包含在下一个合并提交中。但是当我逐个检出提交时,有一点,我的提交就从历史记录中消失了。 - Mad Wombat
也就是说,假设我有提交1、2、3、4、5。 提交1是我的提交。 提交5是当前的 HEAD。 如果我检出5并执行 git log,则会看到1,2,3,4,5。但是如果我检出3,则只会看到2,3,而1不在列表中。 - Mad Wombat
这意味着提交4或5必须是合并提交,其中提交1是其历史的一部分,提交3也是其历史的一部分。同时,提交3具有提交2作为其历史的一部分,但历史中具有提交1。我将编辑添加一个图形片段显示这一点(水平绘制而不是像git log --graph那样垂直绘制)。 - torek
是的,但我希望最终结果中包含我的更改或者有一些记录表明我的更改被删除/还原了。但现在两者都不是这种情况。 - Mad Wombat
如果有帮助的话,我可以粘贴我的提交图的简化版本。 - Mad Wombat
显示剩余2条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接