【问题标题】:How to understand git log --graph如何理解 git log --graph
【发布时间】:2013-11-25 18:13:15
【问题描述】:

我对图形 git log 的输出感到很困惑。

我确实理解每个* 都意味着一个提交,无论是分歧提交、共同提交还是合并提交。 我明白管道意味着分支。

我们来看一个简单的图表日志:

首先,红色管道(最左手的管道)代表哪个分支?我不认为这是我所在的当前分支,因为在我结帐到其他分支后,图表看起来是一样的。此外,它也不代表主分支。

其次,如果最左手分支代表一个分支,为什么它在提交“0e5b5”后会改变颜色?

我搜索了一个关于如何阅读 git 日志图的教程,不幸的是,我什么也没得到。如果有关于这个主题的一些很棒的教程,请随时分享。

【问题讨论】:

  • How to read git log graph的可能重复
  • 添加--decorate 选项以用分支名称标记每个分支头。
  • 边缘图已随 Git 2.25/2.26(2020 年第一季度)发生变化。见my answer below

标签: git git-log


【解决方案1】:

在 Git 2.25(2020 年第一季度)中,“git log --graph”的实现得到了重构,然后其输出得到了简化。

这反过来又可以在某些情况下修复颜色。
以下说明如何使用git log --graph管理颜色和边缘。

commit d784d97(2019 年 11 月 12 日)Denton Liu (Denton-L)
commit bbb13e8,commit 92beecc,commit 479db18,commit 0195285,commit d62893e,commit 0f0f389,commit 458152c,commit ee7abb5,commit 46ba2ab,commit 9157a2a,@987643334@,commit 9157a2a,@98765 987654336@(2019 年 10 月 15 日)James Coglan (jcoglan)
(由 Junio C Hamano -- gitster -- 合并,commit 0be5caf,2019 年 12 月 1 日)

graph: 修复章鱼破折号的颜色

签字人:James Coglan

04005834ed(“log:修复某些章鱼合并形状的着色”,2018-09-01,Git v2.20.0-rc0 -- mergebatch #6 中列出)中,有一个修复用于章鱼合并后的破折号着色。
它区分了所有父级都引入新列的情况与第一个父级合并到现有列中的情况:

| *-.           | *-.
| |\ \          | |\ \
| | | |         |/ / /

后一种情况意味着与前一种情况相比,合并父项的列在 new_columns 数组的左侧开始。

但是,只有当提交的父级在映射到可视列时保持有序时,该实现才有效,因为我们在打印破折号时通过迭代 new_columns 来获得颜色。 一般来说,提交的父级可以任意与现有列合并,并在此过程中更改它们的顺序。

例如,在下图中,每列的编号表示每列中出现哪个提交父项。

| | *---.
| | |\ \ \
| | |/ / /
| |/| | /
| |_|_|/
|/| | |
3 1 0 2

如果列是彩色的(红色、绿色、黄色、蓝色),那么短划线当前将是黄色和蓝色,而它们应该是蓝色和红色。

要解决这个问题,我们需要查找mapping 数组中的每一列,它在GRAPH_COLLAPSING 状态之前指示每个可视列中显示的逻辑列。
这个实现更简单,因为它没有任何边缘情况,而且它还处理左倾斜的第一父母现在如何显示:

| *-.
|/|\ \
| | | |
0 1 2 3

第一个破折号的颜色始终是提交符号右侧两列 mapping 中的颜色。因为提交是在所有边折叠在一起并且可视列与逻辑列匹配后显示的,所以我们可以使用commit_index 找到提交符号的可视偏移量。


关于边缘(仍然使用 Git 2.25,2020 年第一季度):

graph: 提交行上折叠边缘的平滑外观

签字人:James Coglan

当图包含正在向左折叠的边,但这些边与提交线交叉时,效果是边具有锯齿状外观:

*
|\
| *
|  \
*-. \
|\ \ \
| | * |
| * | |
| |/ /
* | |
|/ /
* |
|/
*

当边缘扩展时,我们已经采取措施平滑边缘;当一条边出现在紧跟GRAPH_POST_MERGE 行之后的GRAPH_COMMIT 行上的合并提交标记的右侧时,我们将其渲染为\

* \
|\ \
| * \
| |\ \

我们可以对折叠边进行类似的改进,使它们更易于遵循,并为整个图形增加对称性:

*
|\
| *
|  \
*-. \
|\ \ \
| | * |
| * | |
| |/ /
* / /
|/ /
* /
|/
*

为此,我们为紧跟GRAPH_COLLAPSING 行的GRAPH_COMMIT 行上的边引入了一种新的特殊情况。
通过保留用于在old_mapping 数组中渲染GRAPH_COLLAPSING 线的mapping 数组的副本,我们可以确定一条边缘正在通过GRAPH_COMMIT 线塌陷并且应该被平滑。


更笼统地说:

graph:用于左倾斜合并的提交和合并后行

签字人:James Coglan

引入“左偏”合并之后,即第一个父级与其左侧的另一条边融合的合并,我们在提交的显示和合并后的行。

当前图形代码处理以下提交行上出现在提交右侧 (*) 的边的情况。

2路合并后通常有垂直线

| | |
| * |
| |\ \

章鱼合并(超过两个父级)之后总是有向右倾斜的边:

| |  \          | |    \
| *-. \         | *---. \
| |\ \ \        | |\ \ \ \

如果提交行紧跟在与当前提交相同的列或该提交左侧的任何列中的提交的合并后行之后,则 2 路合并后跟右倾斜边缘:

| *             | * |
| |\            | |\ \
| * \           | | * \
| |\ \          | | |\ \

此提交为提交行引入了以下新案例。如果 2 路合并向左倾斜,则其右侧的边缘始终是垂直线,即使提交遵循合并后线:

| | |           | |\
| * |           | * |
|/| |           |/| |

具有 3 个向左倾斜的父项的提交后面是垂直边缘:

| | |
| * |
|/|\ \

如果 3 向左倾斜合并提交紧跟在合并后行之后,则它可能会跟随右倾斜边缘,就像未倾斜的 2 向合并一样。

| |\
| * \
|/|\ \

Octopus 与 4 个或更多向左倾斜的父级合并后总是会出现右斜边,因为现有列需要围绕合并扩展。

| |  \
| *-. \
|/|\ \ \

在合并后的行上,通常是当前提交斜率之后的所有边都向右:

| * | |
| |\ \ \

但是,如果提交是向左倾斜的 2 路合并,则其右侧的边缘保持垂直。
我们还需要在从提交标记下降的垂直线之后显示一个空格,而这条线通常后面会跟一个反斜杠。

| * | |
|/| | |

如果向左倾斜的合并有超过 2 个父级,则其右侧的边缘仍然是倾斜的,因为它们围绕合并引入的边缘弯曲。

| * | |
|/|\ \ \

要处理这些新情况,我们不仅需要知道每个提交有多少父级,还需要知道它添加到显示中的新列数;此数量记录在当前提交的 edges_added 字段中,以及上一次提交的 prev_edges_added 字段中。

这里,“列”是指可视列,而不是 columns 数组的逻辑列
这是因为即使所有提交的父母最终都与现有边缘融合,它们最初会在提交和合并后行中引入不同的边缘,然后这些边缘崩溃。

例如,一个 3 路合并,其第 2 和第 3 个父项与现有边缘融合仍然会引入 2 个视觉列,这些列会影响其右侧边缘的显示。

| | |  \
| | *-. \
| | |\ \ \
| |_|/ / /
|/| | / /
| | |/ /
| |/| |
| | | |

此合并不引入任何逻辑列;一旦所有边都折叠了,则在此提交之前和之后有 4 条边。但它最初确实引入了 2 个新的边缘,需要由它们右侧的边缘来适应。


经典输出已被简化:

graph:可以简化的图形输出示例

签字人:James Coglan

在此之后的提交引入了对图布局的一系列改进,整理了一些边缘情况,即:

  • 合并其第一个父级与左侧现有列融合
  • 合并其最后一个父级与其右侧的直接邻居融合
  • 在提交行上方和下方向左折叠的边缘

这个测试用例举例说明了这些案例,并提供了一个我想要澄清的历史的激励例子。

合并 E 的第一个父节点与 H 的父节点相同,因此这些边融合在一起。

* H
|
| *-.   E
| |\ \
|/ / /
|
* B

我们可以“倾斜”这个合并的显示,这样它就不会引入其他立即折叠的列:

* H
|
| *   E
|/|\
|
* B

E 的最后一个父节点是 D,与 F 的父节点相同,即合并右侧的边。

* F
|
 \
. \   E
 \ \
 / /
| /
|/
* D

通向 D 的两条边可以更快地融合:与其在合并周围扩展 F 边然后让边塌陷,F 边可以在合并后的线中与 E 边融合:

* F
|
 \
. | E
 \|
 /
|
* D

如果这与上面的“偏斜”效果相结合,我们会得到这些边的更清晰的图形显示:

* F
|
| E
|
|
* D

最后,从 C 到 A 的边在通过 B 的提交线时出现锯齿状:

| * | C
| |/
* | B
|/
* A

这可以被平滑,这样边缘更容易阅读:

| * | C
| |/
* / B
|/
* A

自最近更新日志图呈现代码以来,绘制某些合并开始在不再成立的条件下触发断言,这已在 Git 2.25(2020 年第一季度)中得到纠正。

commit a1087c9commit 0d251c3(2020 年 1 月 7 日)Derrick Stolee (derrickstolee)
(由 Junio C Hamano -- gitster -- 合并到 commit 1f5f3ff,2020 年 1 月 8 日)

graph: 删除 assert() 用于与两个崩溃的父级合并

帮助者:Jeff King
报告者:Bradley Smith
署名者:Derrick Stolee

当 "git log --graph" 显示有两个折叠线的合并提交时,例如:

| | | | *
| |_|_|/|
|/| | |/
| | |/|
| |/| |
| * | |
* | | |

我们触发了一个 assert():

graph.c:1228: graph_output_collapsing_line: Assertion
              `graph->mapping[i - 3] == target' failed.

assert 是由eaf158f8 引入的(“graph API: Use Horizo​​ntallines for more compact graphs”, 2009-04-21, Git v1.6.4-rc0 -- merge),已经很老了。 这个断言试图说明当我们用一个斜线完成一条水平线时,那是因为我们已经达到了我们的目标。

实际上是_second_ 折叠线命中了这个断言。
我们在此代码路径中的原因是因为我们正在折叠第一行,在这种情况下,我们正在达到目标,因为水平线已经完成。
但是,第二行不能是水平线,所以没有水平线会塌陷。在这种情况下,断言我们已经达到了目标是不合适的,因为我们需要在达到目标之前继续另一列。
在这里删除断言是安全的。

0f0f389f12("graph: tidy up display of left-skewed merges", 2019-10-15, Git v2.25.0-rc0 -- merge 列在batch #2) 中的新行为导致导致此断言失败的行为更改。
除了使断言成为可能,它还改变了多条边的折叠方式。

在一个更大的例子中,当前代码将输出如下折叠:

| | | | | | *
| |_|_|_|_|/|\
|/| | | | |/ /
| | | | |/| /
| | | |/| |/
| | |/| |/|
| |/| |/| |
| | |/| | |
| | * | | |

但是,预期的折叠应该允许多个水平线,如下所示:

| | | | | | *
| |_|_|_|_|/|\
|/| | | | |/ /
| | |_|_|/| /
| |/| | | |/
| | | |_|/|
| | |/| | |
| | * | | |

此更改未纠正此行为,但会在以后的更新中注明。


git log --graph”渲染导致合并提交的祖先行不是最佳的,因为最近的更新有点浪费垂直空间,这已在 Git 2.26(2020 年第一季度)中得到纠正。

参见Derrick Stolee (derrickstolee)commit c958d3bcommit 8588932(2020 年 1 月 8 日)。
(由 Junio C Hamano -- gitster -- 合并到 commit d52adee,2020 年 1 月 30 日)

graph: 修复多个边缘的折叠

签字人:Derrick Stolee

此修复解决了previously-added test_expect_failure in t4215-log-skewed-merges.sh

问题在于更新graph_output_collapsing_line() 内部的映射时出现“else”条件。
0f0f389f("graph: 整理显示左倾斜合并", 2019-10-15, Git v2.25.0-rc0 -- merge 列在batch #2) 中,left-skewed 的输出合并已更改为允许第一个父级中的直接水平边缘,由graph_output_post_merge_line()而不是graph_output_collapsing_line()输出。
这将第一行的行为浓缩如下:

0f0f389f之前:

| | | | | | *-.
| | | | | | |\ \
| |_|_|_|_|/ | |
|/| | | | | / /

0f0f389f之后:

| | | | | | *
| |_|_|_|_|/|\
|/| | | | |/ /
| | | | |/| /

但是,当第二个和第三个父边在后面的步骤中折叠时,会出现一个非常微妙的问题。第二个父边现在紧邻垂直边。这意味着条件

} else if (graph->mapping[i - 1] < 0) {

graph_output_collapsing_line() 中评估为假。这种情况的块是我们用水平边缘标记将目标列与当前位置连接起来的唯一地方。

在这种情况下,运行最终的“else”块,边缘被标记为水平,但没有回填目标和当前边缘之间的空白列。
由于第二个父边被标记为水平,第三个父边没有被标记为水平。
这会导致输出继续如下:

在此更改之前:

| | | | | | *
| |_|_|_|_|/|\
|/| | | | |/ /
| | | | |/| /
| | | |/| |/
| | |/| |/|
| |/| |/| |
| | |/| | |

通过在目标列和当前列之间添加“填充”水平边缘的逻辑,我们能够解决问题。

更改后:

| | | | | | *
| |_|_|_|_|/|\
|/| | | | |/ /
| | |_|_|/| /
| |/| | | |/
| | | |_|/|
| | |/| | |

此输出正确匹配0f0f389f 之前的边缘行为的预期混合以及来自0f0f389f 的合并提交渲染。

【讨论】:

  • 这个经过深入研究、具有教育意义且有用的答案曾经获得过零票吗?我不明白,但这是一个赞成票。
  • @DonHatch 谢谢你的好作品。这是基于 James Coglan (jcoglan) 和 Denton Liu (Denton-L) 的工作。
【解决方案2】:

Git 从查看祖先的当前提交开始工作。分支不是“实体”,它们是(移动的)引用。 git log(或具有不同配色方案但类似于 git log --graph 或 tig 的 gitk )无法知道当前分支是分支 A 还是分支 B 的后代。它只知道父母。来自 man git-log:

   git log -p -m --first-parent
       Shows the history including change diffs, but only from the "main 
       branch"   perspective, skipping commits that come from merged
       branches, and showing full diffs of changes introduced by the merges. 
       This makes sense only when following a strict policy of merging
       all topic branches when staying on a single integration branch.

会在一定程度上解决您的问题。 git log 默认使用当前签出的提交作为参考(等同于执行git log HEAD

虽然我个人认为 git 的手册页很清楚,但您可能想看看 gitk 或 tig。前者是一个图形界面,后者是一个类似终端的最小 gitk 工具。我根据自己的意愿使用两者。

【讨论】:

  • 知道为什么它按照 OP 的要求在提交后改变了颜色吗?
  • gitk 中的 git 在每个分叉处改变颜色。这是一个视觉辅助。就像我在回答中所说的那样,在 svn/cvs 的愿景中没有“分支”之类的东西。有父母。在这里,提交 701fe... 是 0e5b5... 和 ba051... 提交的孩子。 git 没有办法“看到” 701fe 的“分支”.. 比 ba051 更多地“成为” 0e5b5... 分支......所以它们是 3 个不同的“历史”,因此有自己的颜色.如果您查看更多分支,颜色会发生变化
【解决方案3】:

首先,红管是哪个分支(最左撇子) 一)代表?我不认为这是我当前的分支 上,因为在我结帐到其他分支后,图表看起来 相同的。此外,它也不代表 master 分支。

红色管道显示您上次提交的来源以及与该来源的任何偏差。因此,当您使用 'git log --graph --all' 时,它可能不会指向当前分支或 master 上的提交。

其次,如果最左手的分支代表单个分支,为什么它会在提交“0e5b5”后改变颜色?

见我上面的回答。最左边的行代表您最后一次提交所在的分支。这条线可以有许多不同的颜色,因为当有偏差时它会改变颜色。它只是在最上面的部分变成红色。

【讨论】:

    猜你喜欢
    • 2017-09-18
    • 2011-06-11
    • 2017-02-07
    • 2020-05-26
    • 2017-09-19
    • 2018-03-11
    • 1970-01-01
    • 2022-10-21
    • 1970-01-01
    相关资源
    最近更新 更多