Я думаю, что это может помочь просмотреть некоторые альтернативные представления графа.
Рассмотрим этот очень простой ромбовидный граф, с более поздними коммитами, нарисованными выше, а более ранними коммитами, нарисованными ниже:
D
/ \
B C
\ /
A
Здесь D
может быть чрезвычайно укороченным хеш-идентификатором коммита слияния, при этом 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
Как и человеческие дети, у "детей" Гита может быть несколько родителей.Однако наиболее типичным случаем является наличие только одного родителя, и в этом случае родитель является первым, последним и единственным родителем.Вы можете назвать его - например, C^1
- это A
- но в этом нет реальной необходимости.Нет C^2
, и запрос об этом просто выдаст вам ошибку.
В сообщениях StackOverflow мне нравится рисовать мои графики с более ранними коммитами в слева и более поздними в right , вот так:
B
/ \
A D <-- master (HEAD)
\ /
C <-- develop
Это дает мне место для вставки названий веток и присоединения слова HEAD
к одному из них, как это обычно делает Git.Однако это затрудняет определение того, какой из родителей является первым, а какой вторым.Обратите внимание, что первая вертикальная диаграмма выше имеет ту же проблему.
Любой коммит с не менее двумя родителями называется merge commit .Здесь используется слово merge как прилагательное, изменяющее commit .Мы также часто будем видеть это как слияние , используя слово merge как существительное.Как отмечает ElpieKay, коммит слияния может иметь более двух родителей, но эти слияния осьминога (как их называет Git) не делают ничего, что вы не можете сделать с помощью только парных слияний, поэтому они в основном простодля хвастовства.:-) Если у вас есть слияние с тремя или более родителями, вы можете пронумеровать их всех.Единственное специальное отличие, которое делает Git сам по себе, - это родительский элемент first , хотя, используя флаг --first-parent
для различных команд Git, таких как git log
.
, git merge
, что смущаеткоманда не должна делать коммит слияния.Он состоит из двух частей, которые я люблю называть слиянием как глагол - актом объединения работы - и последующим совершением коммита.Коммит, который он делает, является коммитом слияния , если вы не укажете ему И, как будто это уже не сбивало с толку, несколько дополнительных команд Git выполняют слияние как глагол , не производя коммит слияния .Поэтому важно иметь в виду различие между формой глагол , для слияния и формой существительного или прилагательного.
Стоит отметить еще несколько пунктов:
Все коммиты - все объекты Git на самом деле - доступны только для чтения.Как только фиксация сделана, ее уже нельзя изменить, потому что ее хэш-идентификатор - как бы его истинное имя - вычисляется путем запуска всех лежащих в его основе данных через хэш-функцию.Если бы вы как-то изменили хотя бы один бит внутри коммита, вы бы получили новый и другой хэш и, следовательно, новый и другой коммит.
Поскольку родитель или родители существуюткогда ребенок сделан, ребенок может записать родителей.
Но так как его ребенок или дети еще не существуют, когда родитель создан, родитель не может записать своих детей.
Именно эти обратные родительские <- дочерние </em> связи формируют граф фиксации. 1
ThisЗначит этоВсе внутренние ссылки Git всегда назад .Git должен начинаться с последнего , дочернего элемента, фиксировать и работать в обратном направлении.Вот почему ветви имена , такие как master
, всегда указывают на tip commit ветви.Поскольку Git работает в обратном направлении, один коммит за раз, слияния, в которых есть два или более родителей, представляют проблему: Git может вернуться только от ребенка к одному из родителей.Обычное решение этой проблемы в Git - поместить всех родителей в очередь, а затем работать с первым коммитом в очереди.
Флаг --first-parent
указывает Git ставить только первый родитель в очередь, игнорируя второго родителя (и любых дополнительных родителей, если это слияние осьминога).Это позволяет Git обходить график коммитов без необходимости иметь более одного коммита за раз.
1 Математически любой граф G являетсяопределяется набором вершин V и ребер E , которые мы записываем как G = (V, E) .Граф может быть направленным , а Git - это: ссылки от вершины к вершине идут только одним путем.Такие ребра называются дугами .В нашем случае я предпочитаю называть вершины узлами; - это сами фактические коммиты, и каждый узел содержит список всех своих исходящих дуг, т. Е. Хэш-идентификаторы родительских коммитов.
Граф коммитов в Git не только направлен , но и ацикличен , что означает, что если мы начнем с любого коммита и пройдемся по графику, мы никогда не вернемся к тому же коммиту,Другими словами, ни один родитель не может быть своим собственным ребенком.Это полезное и важное свойство для различных преобразований графа, которые выполняет Git, поэтому мы иногда говорим о графе фиксации Git как DAG , что сокращенно от Directed Acyclic Graph .График коммитов, или коммит DAG, представляет все снимки, которые вы когда-либо делали.
Обратите внимание, что каждый исходный снимок просто присоединяется к одному коммиту.Графические операции не должны заботиться о , что находится в соответствующих снимках: они смотрят только на сам график!