Ваш график очень хорош, но он вводит в заблуждение.
Давайте начнем с вопроса: на какой ветке синие коммиты?
Это вопрос с подвохом. Они не на ветви, они на нескольких ветвях , во множественном числе. Если вы скажете , что они на ветке A
, ну, это правда, но они также на master
, и большинство из них также на ветке B
.
На вашем чертеже нет идентификаторов для каждого коммита. Из-за этого им трудно говорить: я мог бы сказать «второй серый коммит слева» или «самый правый синий коммит», но это немного громоздко, поэтому позвольте мне перерисовать график как текст, используя по одной заглавной букве в каждом совершить. Я также не буду использовать стрелки здесь, поскольку их слишком сложно сделать в тексте.
A--B--C--D--E--F--G--H--I--J--K--L <-- master
\ \ /
M--N--O--P--Q---R---S <-- branch-A
\ \
T--U--V--W--X--Y--Å--Ø--Z <-- branch-B
То есть tip commit из master
- это commit L
. Коммит tip из branch-A
является коммитом S
. Коммит tip из branch-B
является коммитом Z
.
В Git ветвь name , например master
, всегда указывает на один совершить. Вы получаете на выбор , который коммит; коммит, выбранный таким способом, является tip commit ветви. Любой более ранний коммит, который доступен с , этот совет также находится в ветке. Итак, начиная с L
и работая в обратном направлении - влево на этих чертежах - следуя стрелкам от коммита до коммита, 1 мы go от L
до K
, затем от K
до J
. Но J
- это коммит слияния: у него два родителя, а не один. Таким образом, от J
мы go до S
и I
. От этих двух мы go до H
и R
, и до G
и Q
и F
и P
и E
. Достигнуть E
можно двумя способами, но мы все равно посещаем его только один раз. Отсюда мы можем go на O
и D
, N
и C
, M
и B
и A
. Таким образом, этот список коммитов - это набор коммитов, который находится на master
.
(Обратите внимание, что мы не можем go с Q
до W
, хотя мы можем go в другую сторону, от W
до Q
: все стрелки направлены в одну сторону и направлены назад.)
Набор коммитов на branch-A
начинается с S
и переходит обратно на R
, затем Q
, затем P
, затем E
и O
и D
и N
и так далее. Все эти коммиты также находятся на master
.
Набор коммитов на branch-B
начинается с Z
, перемещается обратно через Ø
и Å
и Y
и X
и W
, затем поднимает P
и V
, а затем E
и O
и U
и так далее. Таким образом, в branch-B
имеется четыре коммита, которых нет ни в одной другой ветви.
1 Технически, все внутренние стрелки Git указывают назад . Итак, вы нарисовали свои стрелки назад, нарисовав их вперед. Situation Эта ситуация возникает из-за того, что коммиты полностью доступны только для чтения: родитель не может заранее знать, какие у него есть sh идентификаторы, которые могут быть у его возможных потомков, но дочерний коммит знает заранее / во время создания, какой родитель имеет sh удостоверения личности, которые есть у ребенка. Таким образом, стрелки должны указывать назад.
(Чтобы двигаться вперед, вы сообщаете Git, где вы хотите оказаться, а затем он движется назад оттуда, чтобы убедиться, что это может закончиться там с какой-то другой отправной точки.)
Как работает git merge
, очень сокращенно
Когда вы запускаете:
git checkout master
git merge branch-B
Git должен найти базу слияния коммит коммитов L
и Z
. Чтобы сделать это, он работает в обратном порядке, как и большинство операций Git, из этих коммитов с ветвями, чтобы найти лучший общий коммит: коммит, который доступен из обеих ветвей ветвей, и, следовательно, в обеих ветвях. , но "ближе всего к подсказкам" как бы. В этом случае, хотя это, возможно, не сразу очевидно, это коммит Q
. Начните с L
, go обратно через K
до J
и затем до S
, затем R
и затем Q
. Между тем, начните с Z
, go обратно до W
и до Q
. Коммиты P
, E
, O
и т. Д. Также находятся в обеих ветвях, но коммит Q
"лучше", потому что это последний такой коммит: он является потомком всех этих коммитов.
Git теперь будет запускать две команды git diff
внутри. Это сравнит базу слияния - commit Q
- с двумя подсказками ветвления:
git diff --find-renames <hash-of-Q> <hash-of-L> # what we changed
git diff --find-renames <hash-of-Q> <hash-of-Z> # what they changed
В этих двух списках различий, если какой-то файл кажется вновь созданным в обоих Советы по ветке, вы получите конфликт добавления / добавления для этого файла. Файл не был в Q
, но это в L
и Z
.
Для файлов, которые находятся во всех трех коммитах, Git попытается объединить любые изменения, показанные в двух наборах различий. Там, где эти изменения не перекрываются (и не «касаются краев»), Git может объединить их. Там, где они перекрываются, но эти перекрытия абсолютно одинаковы - охватывают одинаковые исходные строки в Q
и вносят одинаковые изменения - Git можно объединить, просто взяв одну копию изменения. Все остальные совпадения приводят к конфликтам слияния.
На данный момент ваша задача - разрешать любые конфликты любым способом, каким вам нравится. Например, в конфликтах добавления / добавления всего файла, если два файла совпадают, просто выберите любой из них. Если нет, объедините два файла как-нибудь. Когда вы закончите, запишите окончательное содержимое каждого конфликтующего файла в индекс, используя git add
. Это помечает конфликт индекса как «разрешенный», и теперь вы можете запустить git merge --continue
или git commit
для завершения слияния. 2
2 git merge --continue
проверяет, чтобы убедиться, что вы завершаете слияние. Если нет, то это ошибки. Если да, то он просто запускает git commit
, так что в любом случае нет никакой разницы, если только вы на самом деле не завершаете конфликтующее слияние.