每个git提交都有自己的历史吗?

时间:2016-04-19 09:52:33

标签: git

在手动搜索错误提交时,我发现如果我签出特定提交,则历史记录会发生变化。给定2个分支developpayoff。我将payoff合并到develop中,因此历史记录如下:

A - B - - - E - F - G <- develop
     \     /
      C - D <- payoff

G是我HEAD的当前developCDpayoff中的提交。 E是合并提交。如果我git log,我会看到以下提交:G - F - E - D - C - B - A

然后我结帐F并再次git log。现在我看到了:F - B - A。提交CD未显示。

为什么? (顺便说一下:payoff仍然可用,如果重要,则不会删除)

修改

这是我的git log和我的git log --graph --oneline在HEAD上。

enter image description here

这是在签出提交Commit B之后。

enter image description here

2 个答案:

答案 0 :(得分:2)

  

手工糟糕的提交我..

git有一个内置机制。

平分: https://www.kernel.org/pub/software/scm/git/docs/git-bisect.html

以下是一个演示,用它来查找所需的提交:
https://github.com/nirgeier/Tutorials-bisect

回答你的问题。

每个提交都有自己对提交链中先前提交的引用。 提交也称为 snapshot

enter image description here

  

每个git提交都有自己的历史吗?

您可以在下图中看到git如何存储有关所有提交的信息。

每次提交(快照)都全部提交的内容 这是snapshot

enter image description here

在您的情况下,您有分支导致多次提交。每个分支都指向它自己的提交(快照),它看起来像这样:

enter image description here

答案 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是两个提交的子项,即95704ea43dcf79

4d0be7a时,我们可以看到提交HEADgit 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隐含--graphgit 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;也就是说,不要将每个提交视为存储历史本身,而是要跟踪多个元数据项目:

  • 作者(姓名,电子邮件和日期);
  • 提交者(姓名,电子邮件和日期;通常与作者相同);
  • 父ID列表(这里是粗体,因为这是此特定问题的关键);和
  • 您的提交日志消息。

合并提交是指至少两个父级的任何提交。假设F - develop上的最新提交 - 是合并提交,其两个父项为E,在进行合并之前曾是develop的提示,和D,这仍然是payoff的提示。

提交E记录其(单个)父级,DCBA也是如此。请注意,虽然B有两个孩子CD),但提交他们的父母。为了找到兄弟姐妹或孩子,git必须做一些图形重建工作 - 实际上,我们做的工作与我们首先做的相同。

当你运行git log(没有额外的参数)时,git会以当前提交开头。它使用特殊名称HEAD跟踪当前的提交。通常,HEAD实际上包含分支的名称 - 例如,HEAD引用developpayoff,而分支名称依次指的是特定的承诺。但是当你使用git checkout和特定的提交时,例如E,你会进入&#34;分离的HEAD&#34; mode,现在HEAD包含特定提交的原始SHA-1 ID。

由于git log以当前提交开始,因此提交仅包含其父项&#39; ID,如果我们从E开始并在历史记录中向后工作,我们只会找到E,然后是B,然后是A,这是您观察到的。

您可以告诉git log从其他地方开始:例如,git log payoffpayoff指向的任何提交(在本例中为D)或{{1}开头}以任何提交git log develop指向的方式开始(在本例中为develop)。使用F告诉--all每个引用中找到的每个提交开始。我们还没有定义&#34;参考&#34;在这里,但简短的版本是,这意味着所有分支,所有标签,甚至一些不是分支或标签的特殊情况,例如特殊参考git log使用。