我看到它谈论了很多,但是当我用谷歌搜索含义时,我找不到它。什么是祖先?
我猜分支x的祖先是该分支的任何父母,祖父母,祖父母等等?
那么,如果分支x从主分支分支,分支y从x分支分支,分支z从y分支分支,那么z的祖先是y,x和master?只是猜测一下。
答案 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)
以下内容的真正关键在于意识到分支(或分支名称)不在关系中。提交之间的关系来自 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
是合并提交:它有两个输出弧,分别指向提交E
和G
。然后,从H
开始,我们可以沿着最顶线或最底线走,或者沿着两条线走,然后一直回到根A
。
您可能猜到的这些名称是分支名称。它们充当提示提交的入口点。从提示提交L
开始,我们可以沿最后一行进行操作,但是我们无法到达提交H
-我们从G
到L
进入K
到G
,但是G
仅指向F
,因此我们无法继续发展到H
。所有箭头指向向后。不过,从提交J
开始,我们可以向后退回到H
,然后退回到任一行。
这意味着提交K
和L
仅在develop
上,而提交D
,E
,{{ 1}},H
和I
在主服务器上仅 。所有其他提交都在两个分支上。这就是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
的祖先。例如,在上面的示例中,提交$H1
和J
只是兄弟姐妹: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
或 A
。 D
和A
都不是彼此的祖先,但两者都是D
的祖先。