在手动搜索错误提交时,我发现如果我签出特定提交,则历史记录会发生变化。给定2个分支develop
和payoff
。我将payoff
合并到develop
中,因此历史记录如下:
A - B - - - E - F - G <- develop
\ /
C - D <- payoff
G
是我HEAD
的当前develop
。 C
和D
是payoff
中的提交。 E
是合并提交。如果我git log
,我会看到以下提交:G - F - E - D - C - B - A
。
然后我结帐F
并再次git log
。现在我看到了:F - B - A
。提交C
和D
未显示。
为什么? (顺便说一下:payoff
仍然可用,如果重要,则不会删除)
修改
这是我的git log
和我的git log --graph --oneline
在HEAD上。
这是在签出提交Commit B
之后。
答案 0 :(得分:2)
手工糟糕的提交我..
git有一个内置机制。
平分: https://www.kernel.org/pub/software/scm/git/docs/git-bisect.html
以下是一个演示,用它来查找所需的提交:
https://github.com/nirgeier/Tutorials-bisect
回答你的问题。
每个提交都有自己对提交链中先前提交的引用。
提交也称为 snapshot
。
每个git提交都有自己的历史吗?
您可以在下图中看到git如何存储有关所有提交的信息。
每次提交(快照)都全部提交的内容
这是snapshot
。
在您的情况下,您有分支导致多次提交。每个分支都指向它自己的提交(快照),它看起来像这样:
答案 1 :(得分:2)
编辑:现在我们有了部分图表的快照,我们可以更好地了解正在发生的事情。我认为你被git log
排序它所显示的提交,以及只显示从HEAD
可以访问的提交(或至少部分地)被绊倒(或至少部分)从您列出的任何起点,如果有的话;请参阅此编辑下面的前面的答案。)
图表相当复杂,我懒得重新输入大部分内容,所以这里的一些转换为纯文本(丢失了颜色,但很容易引用)。幸运的是,我正确地转录了缩写的SHA-1(重新输入它们很痛苦)。
* 4d0be7a Commit A
* 2e2be6d Merge remote-tracking branch 'origin/develop' into develop
|\
| * 97504ea Merge branch 'payoff' into develop
| |\
| | * ede23f0 Commit C
| | * 0e1df38 Commit D
[snip]
| * | 9a20c3c Commit x1
[snip - there is another merge in here]
| | * | 0fdd1ff Commit y3
| * | | eed1783 Commit z1
* | | | 43dcf79 Commit B
* | | | bb2bd73 Commit K
注意这些情况下的垂直线(在下面的原始文本中不是水平线),屏幕截图中的颜色是由连接提交节点的垂直条|
构成的。
git log
通常按时间顺序(根据&#34;提交者&#34;时间戳)对提交进行排序,最新的第一次,以便时间戳进一步进入沿着列表向下过去(而不是在水平图中向左移动)。添加--graph
时,git log
会被迫使用拓扑排序。这种类型可能产生不同的结果,特别是在有两个 1 父项的合并提交中。
在git log
拓扑排序中,每个子项提交必须在其任何父项显示之前显示。最顶层的合并2e2be6d
是两个提交的子项,即95704ea
和43dcf79
在4d0be7a
时,我们可以看到提交HEAD
为git log --graph
,它本身不是合并。紧随其后的是2e2be6d
,其中是合并,因此有两个父母。一个父母是97504ea
(另一个合并),另一个是43dcf79
(你的&#34;提交B&#34;)。让我们进一步了解那些提交&#39;父母也是:97504ea
的两个父母是ede23f0
(提交C)和9a20c3c
(提交x1),只是将这些留在我们的脑海中。
合并上的时间戳(通常 2 )比其任一父项上的时间戳更新。这意味着无论您是使用--topo-order
来强制进行地形排序,还是--graph
强制进行拓扑排序,您都会在合并2e2be6d
之前看到合并97504ea
43dcf79
(提交B),您将在97504ea
(提交C)和ede23f0
(提交x1)之前看到合并9a20c3c
。在那之后立即出现了棘手的问题。
没有拓扑订单,您会以什么顺序看到提交B,C和x1?
我们无法从此图表中分辨出来(按地形顺序排序但未显示时间戳)。唯一的方法是查看不同的git log
输出,或检查三次提交的时间戳。幸运的是,我们在其他一个截图中提供了一些信息,特别是第一个包含完整SHA-1 ID和日期字段的截图。不幸的是,显示的日期字段是 author 日期字段,而不是git用于排序的提交者日期字段。幸运的是,这两个可能是相同的。不幸的是,我们没有看到提交x1,但让我们猜测它的日期是&#34;早些时候&#34;。
所以在这里我们有4d0be7a
(提交A)在顶部,最新日期,即4月15日下午。在下面,我们有2e2be6d
(合并),日期为4月15日上午,低于4月14日下午5点之后我们有43dcf79
(承诺B)的日期戳。 (并且所有时区都是+0200,可能是欧洲某处。)我们看不到合并97504ea
:它的时间戳必须早于提交D的时间戳。
因此,当HEAD
指向提交A时,git log
会对这些提交进行排序,以便显示A
,然后其中一个合并 - 具体为2e2be6d
,然后{ {1}},然后是B
,依此类推。添加C
或通过--topo-order
隐含--graph
,git log
会更改其排序,以便先前显示2e2be6d
的父级,包括第二次合并。
如果通过执行其他提交或分支名称的git checkout
,我们会进入图表的其他部分并运行git log
,我们将无法再通过单向链接向上移动达到合并2e2be6d
,这意味着我们无法返回提交B
。这就是B不再出现在输出中的原因。
1 从技术上讲,合并是指具有两个或更多父项的任何提交,但如果您进行&#34;章鱼合并,则只能获得更多#34;我们不用担心这里。
2 我说&#34;通常&#34;因为计算机时钟可能是错误的,并且因为你可以告诉git在任何提交时加上不同的时间戳(过去或将来)。例如,如果您在2038年提交带有时间戳的提交,除非您选择其他排序顺序,否则它将显示在列表的顶部,除非您选择其他排序顺序。
我相信您的合并提交是提交F
,即您可以将其绘制为:
A - B -- E --- F <-- develop
\ /
C - D <-- payoff
主题问题的答案:
每个git提交都有自己的历史吗?
是:&#34;是的,有点,但这可能是错误的提问方式。&#34;也就是说,不要将每个提交视为存储历史本身,而是要跟踪多个元数据项目:
合并提交是指至少两个父级的任何提交。假设F
- develop
上的最新提交 - 是合并提交,其两个父项为E
,在进行合并之前曾是develop
的提示,和D
,这仍然是payoff
的提示。
提交E
记录其(单个)父级,D
,C
,B
和A
也是如此。请注意,虽然B
有两个孩子(C
和D
),但提交仅他们的父母。为了找到兄弟姐妹或孩子,git必须做一些图形重建工作 - 实际上,我们做的工作与我们首先做的相同。
当你运行git log
(没有额外的参数)时,git会以当前提交开头。它使用特殊名称HEAD
跟踪当前的提交。通常,HEAD
实际上包含分支的名称 - 例如,HEAD
引用develop
或payoff
,而分支名称依次指的是特定的承诺。但是当你使用git checkout
和特定的提交时,例如E
,你会进入&#34;分离的HEAD&#34; mode,现在HEAD
包含特定提交的原始SHA-1 ID。
由于git log
以当前提交开始,因此提交仅包含其父项&#39; ID,如果我们从E
开始并在历史记录中向后工作,我们只会找到E
,然后是B
,然后是A
,这是您观察到的。
您可以告诉git log
从其他地方开始:例如,git log payoff
以payoff
指向的任何提交(在本例中为D
)或{{1}开头}以任何提交git log develop
指向的方式开始(在本例中为develop
)。使用F
告诉--all
从每个引用中找到的每个提交开始。我们还没有定义&#34;参考&#34;在这里,但简短的版本是,这意味着所有分支,所有标签,甚至一些不是分支或标签的特殊情况,例如特殊参考git log
使用。