当人们对git说“祖先”时,人们的意思是什么?

问题描述 投票:3回答:2

我已经看到它谈了很多,但当我谷歌的意思,我找不到它。什么是祖先?

我猜测分支x的祖先是分支的任何父母,祖母,祖父母等?

因此,如果分支x从master分支,分支y从x分支,而分支z从y分支,则z的祖先是y,x和master?只是猜一猜。

git
2个回答
5
投票

introduced in April 2005解释说,祖先这个词是第一个用于合并基础的one month later(取代“父母”):

merge-base发现尽可能好的共同祖先。 鉴于选择同样优秀的共同祖先,不应依赖于以任何特定方式作出决定。

“父母”被视为直接的祖先,而合并基础算法需要更进一步。

commit f76412e中所述:

Parent是提交的第一个父级。 我们可以将它命名为(n+1)th生成同一个head_rev的祖先,因为提交是第n代祖先,如果该代数比它已有的名称更好。

August 2005,引入了第一个祖先符号:

[PATCH]添加新的扩展SHA1语法〜

新的符号是<name>的简写,其次是<num>插入符号('^')。 例如。 “master~4”是现任“master”分支机构的第四代祖先,继父母之后;与“master^^^^”相同,但更具可读性。


z的祖先是从z HEAD可以访问的任何提交。

“可达”一词是clarified in 2007

reachable:

据说给定提交的所有祖先都可以从该提交中获得。

更一般地说,如果我们可以通过链接到另一个对象,那么一个对象可以从另一个对象到达,这个链跟随标记到它们标记的任何内容,提交给它们的父母或树,以及树到树或它们包含的blob。

这导致修改distance between two commits的概念:

当提交只有一个相关的父提交时,提交可以达到的提交数量正是父提交的提交数加上一个;而不是在直接单股珍珠上提交count_distance(),我们可以在父母的数量上添加一个。

另一方面,对于合并提交,因为从一个父级可以访问的提交可以从另一个父级访问,所以不能只是添加父级的计数加上一次提交本身;这将超过从多个父母可以到达的祖先。


2
投票

TL;DR

以下内容的真正关键在于意识到分支或分支名称 - 不是关系所在的位置。提交之间的关系来自提交。分支名称只是让您开始使用图表!

Long

除了VonC has said之外,图论还有一个更为一般的描述。 Git存储库中的提交形成有向非循环图或DAG。

图G是节点或顶点V的集合以及连接在顶点之间的一组边E,因此公式G =(V,E)。有向图是用弧代替边的图,即箭头。这是两个维基百科图像。左边的第一个显示了一个常规(无向)图表。第二个显示有向图:

当图形指向时,您只能按箭头指示的方向从一个节点移动到另一个节点。上面的有向图是循环的,因为从任何节点开始,您可以四处移动并在该节点上回退。

非循环图没有循环,即,无论您从哪个节点开始,您都无法返回到您开始的位置。 Git提交形式的图形是有向的和非循环的,因此它是一个DAG。

在Git提交图中,每个节点或顶点都是一个提交,由其哈希ID唯一标识。每个弧及其方向是与节点关联的父提交哈希ID的结果。因此绘制Git图的自然方式是这样的:

... <-F <-G <-H   <-- master

名称master允许你从最后开始,即在提交H,并向后工作。连接弧/箭头作为父指针从节点中出来。

某些提交的祖先是您可以通过跟随箭头达到的任何提交。假设我们有一个更复杂的图形,就像这个一样。我不能在这里正确地绘制内部箭头,但是因为我将更新的节点向右移动,所有箭头指向左侧 - 可能是向左或向上,或向左和向下,但绝对向左。我们的图表如下所示:

        D--E
       /    \
A--B--C      H--I--J   <-- master
       \    /
        F--G--K---L   <-- develop

Commit A是一个没有传出弧的节点。在普通(非Git)图中,这将使它成为叶节点,但Git会向后执行所有操作,因此在Git中,A是根节点。承诺B回到AC指向B,依此类推,直到我们到达H。提交H是一个合并提交:它有两个传出的弧,指向提交EG两者。然后,从H,我们可以走顶线或底线 - 或沿着两条线走 - 然后一直回到根A

正如您可能猜到的,这些名称是分支名称。它们充当提交提交的入口点。从提示提交L我们可以沿着底行工作,但我们无法达到提交H-我们从GLK到达G,但G只指向F - 所以我们无法通过H工作。所有箭头都指向后方。但是,从提交J,我们可以向后工作到H,因此可以向任一行。

这意味着提交KL只在develop,而提交DEHIJ只是在主人。所有其他提交都在两个分支上。这就是VonC所描述的可达性概念。

在数学上,在DAG中,我们定义了前任和后继概念。对于前一个或前一个,我们使用弯曲小于≺的符号:A≺B如果你可以从A到B.我们使用弯曲大于≻(“后继”或“后续”)符号作为相反的符号。这些在图中的节点上定义了partial order。当然,一个节点等于它自己,我们可以说给定一个节点,A = A,还有A≼A和A≽A。

由于Git向后工作,这是相反的:A≺B(A是B的前身),如果你可以从B到A!为了避免每个人都太困惑,Git使用is-ancestor而不是befores。通常,如果将节点与自身进行比较,Git也会将is-ancestor定义为true,以便所有节点都是它们自己的祖先。

因为Git的内部箭头只能向后运行,所以Git不提供is-descendant运算符。你必须逆转is-ancestor测试(但见下文)。如果你想知道“节点X是节点Y的后代”,你可以先问“是Y是X的祖先”。请记住,如果两个哈希ID匹配,is-ancestor会说“是”!

从Git版本1.8.0开始,测试由散列$H1$H2识别的提交是否与此祖先概念相关的简单方法是:

if git merge-base --is-ancestor $H1 $H2; then
    echo commit $H1 is an ancestor of $H2
else
    echo commit $H1 is not an ancestor of $H2
fi

请注意,因为≼仅定义了部分顺序,所以$H1不是$H2的祖先这一事实并不意味着$H2必然是$H1的祖先。例如,在上面的例子中,提交JL只是兄弟姐妹:J不是L的父母,但L也不是J的父母。这意味着如果is-ancestor说“是”,那么你就完成了,但是如果它说“不”,你仍然需要测试反转的案例以决定“是后代”和“是兄弟姐妹”。

您还可以在存储库中具有不相交的子图。这里至少有两个根和至少两个分支提示,但节点之间没有连接:

A--B--C   <-- branch1

D--E--F   <-- branch2

任何顶行提交和任何底行提交之间没有任何关系。但是,如果我们添加合并,从某种意义上说,这会使它们变得相关:

A--B--C
       \
        G   <-- branch1
       /
D--E--F   <-- branch2

现在提交A-B-CD-E-F“与婚姻有关”,因为它与G的合并,因为现在我们可以从G开始并向后工作到ADAD都不是彼此的祖先,但两者都是G的祖先。

© www.soinside.com 2019 - 2024. All rights reserved.