Для слияния, мерзавец находит слияния базу. Обычно это единичная конкретная фиксация. (В некоторых случаях существует несколько кандидатов слияния-база, и мерзавец обрабатывает их тоже, но давайте не будем беспокоиться о них.) Вы можете думать об этом как точка, в которой ваша ветвь и другая ветвь расходились:
На этой диаграмме каждый маленький узел o
обозначает фиксацию. Слияние - это фиксация, отмеченная *
, а не o
. Самая частая фиксация вашей ветки master
является самой правой o
в верхней строке, а наибольшая фиксация их ветви origin/master
является самой правой o
в нижней строке.
Давайте назовем самую частую фиксацию вашей ветки A
, только для конкретности. (Он имеет свой собственный уникальный SHA-1 ID и это его «настоящее имя», но давайте просто называть его A
.) Давайте назовем слияние базы B
и кончик их ветвей C
и перерисовать эту схему:
o - A <-- your branch (master)
/
... - o - B
\
o - o - C <-- their branch (origin/master)
Чтобы выполнить слияние (если требуется слияние), мерзавец начинается с запуска диф между совершить B
и совершить A
, как если бы вы делали git diff B A
(заполнение фактической SHA-1 для B
и A
конечно, и он использует внутренняя версия его кода diff, а не просто чтение через буквальный текст git diff
). Этот diff сообщает git «что вы изменили» с общей базой B
.
Далее git запускает git diff B C
(внутренний формат, конечно же, конечно). Этот diff сообщает git «что они изменили» с той же общей базы.
И, наконец, git пытается объединить два различия. Если вы добавили файл, и они этого не сделали, git сохранит ваш добавленный файл. Если вы изменили правописание neighbor
на neighbour
в файле README
, и они этого не сделали, оно сохраняет ваши изменения. Если они удалили файл, который вы не касались, или удалили строку из файла, который вы не коснулись, git сохраняет их изменения. Если вы оба сделали точно такой же изменить на weather.h
, git держит один экземпляр этого изменения (а не двух экземпляров). Git применяет все «сохраненные» изменения к базовой версии и записывает результат в ваше рабочее дерево, а слияние теперь выполняется без конфликтов слияния. Результат, по мнению git, готов к совершению. (Обратите внимание, что это верно, даже если некоторые изменения, которые вы сделали, требуют, скажем, чтобы система сохраняла удаленный файл, который git теперь удалил. То есть предположим, что они сказали: «О, смотрите, этот файл не используется, давайте уберем его »и вы сказали:« О, oops, я забыл использовать этот файл, давайте использовать его ». Git не знает, что эти изменения действительно конфликтуют: все, что он может сказать, это то, что строки в diff don ' t сталкиваются.)
Следующий шаг зависит от того, был ли вы задан флаг --no-commit
. Это подавляет фиксацию, несмотря ни на что. Если вы не подавляли фиксаций, git merge
совершает это множество не-очевидно-конфликтных изменений, как «слияние совершить», который имеет два родителей:
o - A ----- M <-- your branch (master)
/ /
... - o - B /
\ /
o - o - C <-- their branch (origin/master)
На данный момент, рабочее дерево соответствует новой фиксации M
. Пока он не был проверен , было проверено в (совершено) как слияние.
Если вы сделали, скажите --no-commit
, или если произошел конфликт слиянием, слияние прекратится и вы сможете исправить и/или совершить слияние. Изменения просто присутствуют в вашем рабочем каталоге. Если и когда вы решите зафиксировать результат, это будет слияние. Гит знает это, потому что он оставляет файл трассировки, говорящий «в середине слияния». Если вы решили отменить слияние с git merge --abort
, это приведет к удалению трассировочного файла.
Для перестановки git проходит аналогичный процесс. Однако вместо того, чтобы найти базу слияния, он находит набор коммитов, которые у вас есть, что нет. Мы можем сделать эту схему еще раз, но давайте использовать различные имена узлов:
A - B <-- your branch (master)
/
... - o - o
\
C - D - E <-- their branch (origin/master)
В этом случае мерзавец находит ваши два фиксаций (A
и B
) и копии их (с помощью git cherry-pick
, более или менее). Механизм для этого потенциально сложный, поэтому давайте просто отметим здесь, что каждая операция cherry-pick
требует обновления вашего рабочего дерева и создания нового коммита. Если все пойдет хорошо, мы вышлем копию A
, A'
и копию B
B'
; git перемещает название ветки, указывая на B'
; и окончательный рисунок выглядит следующим образом:
A - B [abandoned]
/
... - o - o A' - B' <-- your branch
\ /
C - D - E <-- their branch
Поскольку каждый шаг вишневого драфта обновляет рабочее дерево и делает коммит из нее, ваша работы дерево соответствует окончательному обязательству B'
, не потому, что он получил проверило из, но потому, что он был проверен в (совершенный), точно так же, как в случае слияния.
(1) ветви (включая текущую ветку) всегда хранятся в репозитории git, а рабочий каталог не находится в репозитории git. Поэтому я не уверен, понимаю ли я, что «Текущая ветка находится в рабочем каталоге». (2) Мой вопрос заключается в моей мысли о том, что шаг слияния изменяет текущую ветвь в репозитории git, в то время как рабочий каталог не обновляется с текущей ветвью, поэтому необходимо проверить измененную текущую ветку на рабочий каталог. Но я не уверен, что этот шаг слияния «git pull» делает это уже, или я должен делать это сам после «git pull». – Tim
Я отредактировал язык в своем ответе. Я говорю, что содержимое в рабочем каталоге * всегда * отражает состояние текущей ветви (если, очевидно, если нет текущей ветви). –
«git будет проверять, что совершить», вы имеете в виду шаг слияния git pull делает это уже, или я должен делать это сам после git pull? – Tim