我认为查看图表的一些替代演示可能会有所帮助。
考虑这个非常简单的菱形图,后来的提交绘制得更高,早期的提交绘制得更低:
D
/ \
B C
\ /
A
Here, D
可能是合并提交的极其缩短的哈希 ID,其中B
and C
是它的两个输入(用 Git 的术语来说是两个父项)。A
是两者的(一个,单亲)父母B
and C
。因此,B
and C
are 兄弟姐妹,或者如果 Git 直接使用这个概念的话:两者都有相同的父母,所以他们一定是兄弟姐妹(或者两个兄弟或两个姐妹或其他什么)。但 Git 通常不会以这种方式谈论提交——它通常只对直接的父/子关系感兴趣。
我们可以——并且git log --graph
也可以将其绘制为:
* d...... fourth message
|\
| * c...... third message
* | b...... another message
|/
* a...... some commit message
就像人类的孩子一样,Git 的“孩子”可以有多个父母。然而,最典型的情况是one父级,在这种情况下,该父级是第一个、最后一个、也是唯一的父级。你can编号——C^1
is A
,例如,但没有真正的需要。没有C^2
并要求它只会给你一个错误。
在 StackOverflow 帖子中,我喜欢用较早的提交来绘制图表left以及后来的right, 像这样:
B
/ \
A D <-- master (HEAD)
\ /
C <-- develop
这给了我插入分支名称并附加单词的空间HEAD
到其中之一,就像 Git 通常所做的那样。然而,这使得很难区分哪个父母是第一个,哪个是第二个。请注意,上面的第一个垂直图也存在同样的问题。
任何提交at least两个父母被称为合并提交。这使用了这个词merge作为形容词,修饰commit。我们也会经常看到它a merge,使用这个词merge作为名词。正如 ElpieKay 所指出的,合并提交可以有两个以上的父项,但是这些章鱼合并(正如 Git 所说的那样)不要做任何你用成对合并做不到的事情,所以它们大多只是为了炫耀。 :-) 当您确实与三个或更多父母合并时,您可以对所有父母进行编号。 Git 本身唯一的特殊区别是first不过,家长使用--first-parent
标记各种 Git 命令,例如git log
.
令人困惑的是,git merge
命令不必进行合并提交。它有两个部分,我喜欢参考合并作为动词——合并工作的行为——然后做出承诺。它所做的提交是合并提交除非你告诉它不要这样做。而且,好像这还不够令人困惑,还有几个额外的 Git 命令可以执行以下操作:合并作为动词部分不产生合并提交。因此,记住两者之间的区别很重要verb form, to merge,以及名词或形容词形式。
还有几项值得注意:
所有提交(实际上是所有 Git 对象)都是只读的。一旦提交,就永远无法更改,因为它的哈希 ID(可以说是它的真实名称)是通过哈希函数运行其所有基础数据来计算的。如果您要以某种方式更改提交中的任何一个位,您都会得到一个新的不同的哈希值,从而获得一个新的不同的提交。
由于创建孩子时父母就已经存在,因此孩子可以记录父母。
但由于创建父级时其子级还不存在,因此父级无法记录其子级。
It's these backwards parent <- child linkages that form the commit graph.1
这意味着 Git 的内部链接始终是向后. Git must开始于last,最孩子气,承诺并逆向工作。这就是为什么分支names like master
总是指向提示提交的分支机构。由于 Git 向后工作,一次一次提交、合并(有两个或多个父级)会出现一个问题:Git 只能从子级移回到one父母的。 Git 通常解决这个问题的方法是放置all将父级放入队列中,然后处理队列中的第一个提交。
The --first-parent
标志告诉 Git 仅放置first将父级放入队列中,忽略第二个父级(如果这是章鱼合并,则忽略任何其他父级)。这使得 Git 可以遍历提交图,而无需一次处理多个提交。
1Mathematically, any graph G is defined by a collection of vertices V and edges E, which we write as G = (V, E). A graph can be directed, and Git's is: the links from vertex to vertex go only one way. Such edges are called arcs. In our case I prefer to call the vertices nodes; these are the actual commits themselves, and each node contains a list of all its outgoing arcs, i.e., the hash IDs of the parent commits.
Git 提交图不仅directed但是也acyclic,这意味着如果我们从任何一个提交开始并遍历图表,我们将永远不会返回到同一提交。换句话说,没有父母可以成为自己的孩子。对于 Git 所做的各种图形转换来说,这是一个有用且重要的属性,因此我们有时将 Git 提交图称为DAG,这是缩写有向无环图。提交图或提交 DAG 代表您曾经创建的所有快照。
请注意,每个源快照仅附加到一次提交。图操作不必关心相应快照中的内容:他们只查看图表本身!