在涵盖相对提交引用的 Udacity 课程中,它说:
^ 表示父提交,~ 表示第一个父提交
^ 和 ~ 之间的主要区别在于何时从合并创建提交。合并提交有两个父项。对于合并提交,^ 引用用于指示提交的第一个父项,而 ^2 指示第二个父项。第一个父级是您运行 git merge 时所在的分支,而第二个父级是合并到的分支。
基于在git log --oneline --graph
命令行上运行的以下输出:
使用 SHA 的提交f69811c
是 HEAD~4^2 相对于(最顶层,带有头指针)提交9ec05ca
。合并提交1a56a81
的第二个父项是f69811c
,课程解释了这一点“HEAD~4 引用了当前提交的第四个父项提交,然后 ^2 告诉我们它是合并提交的第二个父项(被合并到)”
根据以黄色引用的课程文本,它似乎e014d91
是1a56a81
的第一个父级,因为它是与合并提交具有相同分支的父级。
根据这些信息,e6c65a6
的关系1a56a81
是什么?
我不认为它也是第二个父母(如果可以有多个第一和第二个父母......),即使它也是合并到 master 的分支,因为该答案在课程测验中被拒绝。
另外,如果我是正确的,e014d91
是1a56a81
第一个母公司,是什么的关系2097521
,并3772ab1
以1a56a81
(这似乎他们也第一次家长,再次,如果合并提交其实可以有多个父)?
我认为查看图表的一些替代表示可能会有所帮助。
考虑这个非常简单的菱形图,后面的提交绘制得更高,而更早的提交绘制得更低:
D
/ \
B C
\ /
A
Run Code Online (Sandbox Code Playgroud)
在这里,D
可能是合并提交的极其缩短的哈希 ID,有B
和C
是它的两个输入(两个父项,在 Git 的术语中)。 A
是(一个,单)两者的亲B
和C
。因此,B
和C
是兄弟姐妹,或者如果 Git 直接使用这个概念:两者都有相同的父母,所以他们必须是兄弟姐妹(或两个兄弟或两个姐妹或其他)。但是 Git 通常不会以这种方式谈论提交——它通常只对直接的父/子关系感兴趣。
我们可以——而且git log --graph
确实——也将其绘制为:
* d...... fourth message
|\
| * c...... third message
* | b...... another message
|/
* a...... some commit message
Run Code Online (Sandbox Code Playgroud)
就像人类的孩子一样,Git 的“孩子”可以有不止一个父母。然而,最典型的情况是只有一个父节点,在这种情况下,父节点是第一个、最后一个和唯一的父节点。你可以编号IT-C^1
是A
,例如,但没有真正的需要。没有C^2
,要求它只会让你出错。
在StackOverflow的贴子,我喜欢我的画与图形在较早提交留在与后来者的权利,就像这样:
B
/ \
A D <-- master (HEAD)
\ /
C <-- develop
Run Code Online (Sandbox Code Playgroud)
这给了我插入分支名称的空间,并将单词附加HEAD
到其中一个,就像 Git 通常所做的那样。但是,这使得很难分辨哪个父对象是第一个,哪个是第二个。请注意,上面的第一个垂直图也有同样的问题。
任何具有至少两个父级的提交都称为合并提交。这使用单词merge作为形容词,修改commit。我们也会经常看到它只是一个 merge,使用单词merge作为名词。正如 ElpieKay 所指出的,一个合并提交可以有两个以上的父项,但是这些章鱼合并(正如 Git 所称的那样)不会做任何你无法通过成对合并做的事情,所以它们主要是为了炫耀。:-) 当您确实与三个或更多父母合并时,您可以对所有父母进行编号。不过,Git 本身唯一的特殊区别是对于第一个父级,使用--first-parent
标记各种 Git 命令,例如git log
.
令人困惑的是,该git merge
命令不必进行合并提交。它有两个部分,我喜欢将其称为动词——合并工作的行为——然后进行提交。它所做的提交是合并提交,除非您告诉它不要。而且,好像这还不够令人困惑,几个额外的 Git 命令将合并作为动词部分进行,而不会产生合并提交。所以记住动词形式、合并和名词或形容词形式之间的区别很重要。
值得注意的还有几个项目:
所有提交——所有 Git 对象,真的——都是只读的。一旦进行了提交,就永远无法更改,因为它的哈希 ID(它的真实名称)是通过通过哈希函数运行其所有底层数据来计算的。如果您要以某种方式更改提交中的任何一点,您就会得到一个新的不同的哈希值,因此会得到一个新的不同的提交。
由于在制作孩子时父母或父母存在,因此孩子可以记录父母。
但是由于在创建父项时其子项或子项还不存在,因此父项无法记录其子项。
正是这些向后的父 <- 子链接形成了提交图。1
这意味着 Git 的内部链接始终是向后的。Git必须从最后一个、最孩子的提交开始,然后向后工作。这就是为什么分支名喜欢master
总是点到尖提交的分支。正如吉特倒过来,一个承诺的时间,合并,它有两个或更多的家长,现在一个问题:混帐只能从孩子搬回一个家长。Git 对这个问题的通常解决方案是将所有父项放入一个队列,然后处理队列中的第一个提交。
该--first-parent
标志告诉 Git 只将第一个父节点放入队列,忽略第二个父节点(如果这是章鱼合并,则忽略任何其他父节点)。这允许 Git 遍历提交图,而无需一次处理多个提交。
1 在数学上,任何图G都由顶点V和边E的集合定义,我们将其写为G = (V, E)。图可以是有向的,而 Git 是:从顶点到顶点的链接只有一种方式。这样的边称为弧。在我们的例子中,我更喜欢调用顶点节点;这些是实际的提交本身,每个节点都包含其所有输出弧的列表,即父提交的哈希 ID。
Git 的提交图不仅是有向的,而且是无环的,这意味着如果我们从任何一个提交开始,并遍历该图,我们将永远不会返回到同一个提交。换句话说,没有父母可以是自己的孩子。对于 Git 进行的各种图转换来说,这是一个有用且重要的属性,因此我们有时将 Git 提交图称为DAG,它是Directed Acyclic Graph 的缩写。提交图或提交 DAG 表示您曾经制作的所有快照。
请注意,每个源快照都简单地附加到一个提交。图操作不必关心相应快照中的内容:它们只查看图本身!