Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
提交DAG如何存储在GIT中_Git_Directed Acyclic Graphs - Fatal编程技术网

提交DAG如何存储在GIT中

提交DAG如何存储在GIT中,git,directed-acyclic-graphs,Git,Directed Acyclic Graphs,DAG是如何在Git内部存储的? 作为一个例子,考虑DAG A->B->C->D ->E->F->G 您需要以某种方式保存以下信息。A->B,B->C,C->D,A->E,E->F,F->G。 那么它是如何存储的呢?给定一个特定的节点,你怎么知道它在哪个分支上呢?这样我们就不会在术语中迷失:DAG通常是一个图G=(V,E),由顶点集V和边集E组成,其中边集中的每条边都施加一个方向(也称为弧),并且没有循环(没有从任何顶点通过各种圆弧返回到自身的路径)。边的典型表示形式为顶点对,例如,如果节点表示

DAG是如何在Git内部存储的? 作为一个例子,考虑DAG A->B->C->D ->E->F->G

您需要以某种方式保存以下信息。A->B,B->C,C->D,A->E,E->F,F->G。
那么它是如何存储的呢?给定一个特定的节点,你怎么知道它在哪个分支上呢?

这样我们就不会在术语中迷失:DAG通常是一个图G=(V,E),由顶点集V和边集E组成,其中边集中的每条边都施加一个方向(也称为弧),并且没有循环(没有从任何顶点通过各种圆弧返回到自身的路径)。边的典型表示形式为顶点对,例如,如果节点表示为单个大写字母(如您的示例中所示)我们可以在边集合E中,用以表示顶点A在那个方向上连接到顶点B,也就是说,从A到B有一条弧

Git不使用这种典型的表示法。相反,每个“顶点”都是一个提交,其唯一标识符是其哈希ID(至少我倾向于在图中称这些“节点”而不是“顶点”)。每个提交都会根据其哈希ID列出其父提交。因此,如果提交
a
(真的
a234567890123456789012345678901234567890
或类似的东西)是commit
B
(真的
b876543210…
),在
A
命名
B
中没有任何内容,但在
B
命名
A
中有父ID

换句话说,Git图中的边都是向后的

同时,分支名称指向单个提交节点,该节点被指定为该分支的提示提交。例如,
master
可以解析为
08bb3500a2a718c3c78b0547c6801cafa7a8fd9

名称
HEAD
包含当前分支名称,或者包含当前提交的原始哈希ID。使用
git rev parse
,我们可以将任何名称(包括
HEAD
)转换为适当的ID:

$ git rev-parse HEAD
08bb3500a2a718c3c78b0547c68601cafa7a8fd9
我们现在可以回答以下问题:

那么它是如何存储的呢

提交节点作为类型为
commit
的对象存在于存储库中,其内容(在通常的压缩扩展后)仅为纯文本,格式如
git cat file-p
所示:

$ git cat-file -p HEAD | sed 's/@/ /'
tree a775288b86ae652ea163357939d852cdd927eed6
parent 36cafe44443fcca9eb35399ef0e9bfe289ec5dde
author Junio C Hamano <gitster pobox.com> 1468959976 -0700
committer Junio C Hamano <gitster pobox.com> 1468959976 -0700

Sixth batch of topics for 2.10

Signed-off-by: Junio C Hamano <gitster pobox.com>
$git cat文件-p HEAD|sed's/@/'
树a775288b86ae652ea163357939d852cdd927eed6
父项36CAFE4443FCCA9EB35399EF0E9BFE289EC5DDE
作者Junio C Hamano 1468959976-0700
提交人Junio C Hamano 1468959976-0700
2.10的第六批主题
签字人:Junio C Hamano
这告诉我们,从
08bb3500a2a718c3c78b0547c68601cafa7a8fd9
36CAFE4443FCCA9EB35399EF0E9BFE289EC5DDE
有一个弧

要找到所有边和顶点/节点的完整图形,我们从所有合适的起点开始(见下文)并从存储库中读取这些对象。对于提交对象,我们读取它们的
行,这些行提供了额外的节点ID,还提供了一个弧:从我们刚刚读取的节点,到每个
行中命名的节点。(合并提交有多个
parent
行,而不是一个列有多个ID的
parent
行,但这当然很简单。还要注意,每个带注释的标记对象都指向另一个对象,通常是一个提交,所以当我们找到
tag
类型的对象时,我们应该读取它的
对象
行,然后重复一次在找到一个非标记对象之前,我们不会执行此过程。但是,如果仅从分支名称开始,我们将找不到任何此类对象;请参见下文。)

(在正常的非Git DAG中,没有特别区分弧,但在Git中,为每个节点列出的第一个父节点与任何其他父节点是不同的,并且在使用后缀-
^
语法时顺序很重要。特别是,当您进行合并提交时,以前是
头的ID将成为n的第一个父节点ew合并提交。)

给定一个特定的节点,您如何知道它在哪个分支上

这个问题有一个缺陷:它假设节点位于分支上

事实上,一个节点可能不在分支上,也可能在多个分支上

现在让我们回到所有合适的起始点的概念上。有什么起始点?如果我们有一个典型的图形表示,我们将拥有完整的顶点集(或节点集)列在某个地方。在Git中,我们没有这个。1相反,我们有引用,大部分是以
refs/
开头的名称。分支和标记是引用的形式,分别以
refs/heads/
refs/tags/
开头。Git命令
Git for each ref
可以找到所有这些引用。

有一些特殊用途的引用不以
refs
开头:
HEAD
MERGE\u HEAD
CHERRY\u PICK\u HEAD
ORIG\u HEAD
,等等。一些Git命令也需要在这里查看。但是,对于您的特定情况,我们只关心分支名称,所有这些都以开头e> refs/
-事实上,使用
refs/heads/
-我们可以为每个ref-refs/heads运行
git来列出它们。(每个ref
命令在这里为我们添加了额外的
/
,理论上它类似于目录列表操作。)

因此,要确定节点X(对于某些X)是否位于一个或多个分支上,如果是,则从存储在每个分支名称下的节点ID开始。该ID标识该分支的提示提交。然后,我们遵循该提交的父节点,以及这些节点的父节点,依此类推,直到父节点用完为止(使用我们喜欢的任何搜索算法).如果我们在途中遇到节点X,则节点X位于该分支上

因此,节点X包含在每个分支中,我们可以从该分支的tip commit开始找到X

(标记名通常指向