人们对git说“祖先”是什么意思?

时间:2019-03-17 01:39:11

标签: git

我看到它谈论了很多,但是当我用谷歌搜索含义时,我找不到它。什么是祖先?

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

那么,如果分支x从主分支分支,分支y从x分支分支,分支z从y分支分支,那么z的祖先是y,x和master?只是猜测一下。

2 个答案:

答案 0 :(得分:5)

祖先一词最初是introduced in April 2005的合并基础(替换“父”),one month later解释:

  

合并基础可以找到尽可能好的共同祖先。
  如果选择了同样优秀的共同祖先,就不应依赖它   以任何特定方式做出决定。

“父母”被视为直接祖先,而基于合并的算法则需要回溯到更远的地方。

commit f76412e中所述:

  

父级是提交的第一个父级。
  我们可以将其命名为(n+1)th的世代祖先,如果该世代号比已有的名字好,则与commit是其第n代祖先的head_rev一样。

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

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

  

新符号是<name>的缩写,后跟<num>脱字符('^')字符。
  例如。 “ master~4”是当前“ master”分支头的第四代祖先,紧随其后。与“ master^^^^”相同,但可读性更高。


z的祖先是z HEAD可以到达的任何提交。

“可达”一词是clarified in 2007

reachable:
     

一个给定提交的所有祖先都可以从该提交到达。

     

更笼统地说,如果我们可以通过一条链从另一个物体到达另一个物体,那么该链就跟随标签到它们所标记的任何东西,提交给它们的父代或树木,以及树到它们所包含的树木或斑点。

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

  

当一个提交只有一个相关的父提交时,该提交可以达到的提交数恰好是父级可以达到的提交数加一;与其对单个珍珠串上的提交运行count_distance(),我们只需在父母数量上加一个即可。

     

另一方面,对于合并提交,由于可以从一个父级访问的提交可以从另一个父级访问,因此您不能仅将父级的计数加一个提交本身;这样会使来自多个父母可以联系的祖先的人数过高。

答案 1 :(得分:2)

TL; DR

以下内容的真正关键在于意识到分支(或分支名称)不在关系中。提交之间的关系来自 commits 。分支名称可以帮助您快速进入图表!

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

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

{p {0}}

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

非循环图没有循环,即,无论您从哪个节点开始,都永远无法回到起点。 Git提交的图形的类型是有向且无环的,因此它是DAG。

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

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

名称 master让您从结尾开始,即,在提交H处开始,然后向后工作。连接的弧/箭头作为 parent 指针从节点出来。

某个提交的祖先是您可以通过遵循箭头进行的任何提交。假设我们有一个更复杂的图,像这样。我无法在此处正确绘制内部箭头,但是由于我将较新的节点向右绘制,因此所有箭头都指向左-可能是左上,上,左或下,但肯定是左上。我们的图看起来像这样:

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

提交A是没有外向弧的节点。在普通(非Git)图中,这将使其成为 leaf 节点,但是Git向后进行所有操作,因此在Git中,A root 节点。提交B指向A,指向C指向B,依此类推,直到到达H。提交H合并提交:它有两个输出弧,分别指向提交EG。然后,从H开始,我们可以沿着最顶线或最底线走,或者沿着两条线走,然后一直回到根A

您可能猜到的这些名称是分支名称。它们充当提示提交的入口点。从提示提交L开始,我们可以沿最后一行进行操作,但是我们无法到达提交H-我们从GL进入KG,但是G仅指向F,因此我们无法继续发展到H。所有箭头指向向后。不过,从提交J开始,我们可以向后退回到H,然后退回到任一行。

这意味着提交KL仅在develop上,而提交DE,{{ 1}},HI在主服务器上仅 。所有其他提交都在两个分支上。这就是VonC正在描述的 reachability 概念。

在数学上,在DAG中,我们定义前辈后继概念。对于前身或前身,我们使用小于bent的符号:A≺B(如果可以从A转到B)。相反,使用大于bent的符号(“ successor”或“ succeeds”) 。它们在图形的节点上定义partial order。当然,一个节点等于自己,可以说给定一个节点,A = A,但也有A≼A和A≽A。

由于Git向后工作,因此情况相反:如果可以从B转到A,则A≺B(A是B的前身)!为了避免每个人都感到困惑,Git使用 is-ancestor 而不是 precedes 。通常,如果您将节点与自身进行比较,Git还将 is-ancestor 定义为true,以便所有节点都是其自己的祖先。

由于Git的内部箭头仅向后工作,因此Git不提供 is-descendant 运算符。您必须颠倒 is-ancestor 测试(但请参见下文)。如果您想知道“节点X是节点Y的后代”,则可以从询问“是Y是X的祖先”开始。请记住,如果两个哈希ID匹配,则is-ancestor说“是”!

从Git 1.8.0版开始,测试由哈希J$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的祖先。例如,在上面的示例中,提交$H1J只是兄弟姐妹:L不是J的父级,但是L不是父级的L。这意味着,如果is-ancestor说“是”,则说明您已经完成,但是如果它说“否”,则您仍然必须测试相反的情况才能在“是后代”和“是同级”之间做出决定。

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

J

任何顶行提交与任何底行提交之间都没有关系。但是,如果我们添加 merge ,从某种意义上说,它们使它们成为相关:

A--B--C   <-- branch1

D--E--F   <-- branch2

现在,A--B--C \ G <-- branch1 / D--E--F <-- branch2 A-B-C的提交“与婚姻相关”,合并在D-E-F,因为现在我们可以从G开始工作向后退至G ADA都不是彼此的祖先,但两者都是D的祖先。