Чтобы суммировать комментарии и ответить на вопрос как задано ...
Поиск базы слияния
Git вычисляет базу слияния пары коммитов с использованием алгоритма для поиска самого низкого общего предка направленного ациклиуса c График. Точный алгоритм нигде не описан и может измениться, пока новый дает правильные результаты. См. Также Алгоритм поиска наименьшего общего предка в направленном графике ацикли c?
Может быть несколько LCA. В этом случае стратегия слияния -s resolve
выбирает одну из них. Вы не можете контролировать, какой из них он выбирает. Стратегия слияния -s recursive
запускает на них git merge
по два, как если бы это было следующим:
commits=$(git merge-base --all $left $right)
if len($commits) > 1
a=$commits[0]
for i in range(1, len(commits))
b=$commits[i]
a=$(git-merge-recursively-inner $a $b)
rof
commits=($a)
fi
(в псевдокоде). Обратите внимание, что внутреннее рекурсивное слияние само может найти более одной базы слияния; если это так, он использует этот алгоритм для их объединения.
Окончательный результат - один коммит, $commits[0]
. Это база слияния.
В любом случае, теперь, когда у нас есть единая фиксация базы слияния - из алгоритма нахождения LCA, который нашел только один LCA, или с помощью рекурсивного слияния слиянием множественные базы слияния, которые возникли из алгоритма LCA-поиска, или путем разрешения слияния, просто выбрав один коммит из списка - мы можем посмотреть, как git merge-(recursive|resolve)
на самом деле объединяет файлы. Он должен выполнить две внутренние операции git diff
, каждая с включенным детектором переименования.
Различия и идентификация файла / обнаружение переименования
A разница файла Движок сравнивает два файла. Мы помещаем один файл слева и другой файл справа. Там, где два файла совпадают, diff ничего не говорит. Там, где два файла различаются, механизм различий - в зависимости от того, насколько он хорош - предлагает набор изменений, которые мы можем применить, чтобы содержимое левой стороны соответствовало содержимому правого файла.
Для сравнения пара совершает , Git ставит один слева и один справа. Затем он должен выполнить сопряжение файлов в этих двух коммитах. Git может сделать это с включенным детектором переименования, или нет.
Изображение довольно четкое, когда детектор переименования отсутствует. Файлы слева и справа являются «одним и тем же файлом», если и только если они имеют одинаковое имя . Добавление детектора переименования идентифицирует (помечает как «одинаковые») некоторые файлы с левой и правой сторон от diff, даже если names изменились.
Git Существующий детектор переименования претерпевает некоторые изменения, чтобы сделать его лучше. Точных подробностей здесь не требуется: все, что нам нужно знать, - это то, что некоторые файлы будут переименованы, так что это «один и тот же» файл, даже если они имеют разные имена. Другие файлы автоматически становятся «одним и тем же» файлом, потому что они имеют одинаковые имена.
Для каждого парного файла механизм различий производит набор изменений, которые превращают файл левой части в правую часть. файл. Детектор переименования производит операции переименования, которые должны быть выполнены первыми. Файлы, которые new справа, называются добавлено , а файлы, которые существовали при фиксации слева, но не существуют при фиксации справа, удаляются.
Следовательно, diff-of-pair-of-commits приводит к:
- файлам для переименования (от старого имени к новому имени)
- файлов для добавления
- файлы для удаления
плюс некоторые наборы изменений для файлов, которые существуют в обеих фиксациях, при необходимости.
Объединение с учетом базы объединения
При единой фиксации базы слияния как разрешение, так и рекурсивный процесс выполняются одинаково:
- Различает базу слияния с
HEAD
с включенным обнаружением переименования. Это наши изменения. - Отличить базу слияния от других коммитов с включенным обнаружением переименования. Это их изменения.
- Объединение изменений.
«Объединение» требует учета как изменений высокого уровня, таких как переименование, добавление и удаление, так и изменений низкого уровня в одном файле. Файл, к которому будут применены объединенные изменения, является файлом из базы слияния . Это гарантирует, что результат работает во всех случаях.
Например, предположим, что мы переименовали файл, а они изменили файл, который мы переименовали. Объединенные изменения говорят, что, по сути, в конце, переименуйте файл base.ext в head.ext; тем временем измените строку 17 из base.ext. Таким образом, мы изменим строку 17 и переименуем файл, захватывая оба действия.
Операции высокого уровня могут конфликтовать! Например, если мы переименуем файл, а они его удалят, это конфликт высокого уровня. Если и мы, и они переименовывают файл, это конфликт, если мы оба не выбрали одно и то же окончательное имя. Если и мы, и они удаляют файл, это хорошо сочетается с очевидным результатом.
Низкоуровневые изменения также могут конфликтовать. Конфликт возникает, если мы и они оба изменяем одни и те же строки по-разному, или если наши изменения и их изменения «соприкасаются» с обеих сторон. Например, если мы заменим строки 9 и 10 (удалите 2 строки после строки 8 и вставим 2 строки после строки 8), а они заменят строки 11 и 12, наши изменения упираются. Из общей осторожности называет это конфликтом.
Конечно, если мы и они сделаем одинаковые изменения в одинаковых исходных строках, это не конфликт , Git просто берет одну копию этих изменений.
Расширенная опция -Xours
или -Xtheirs
разрешает конфликты низкого уровня, выбирая одну сторону (нашу или свою), игнорируя другую. Это работает только для конфликтов низкого уровня. Логично, что это может относиться и к конфликтам высокого уровня, но это не так.
Объединив все наши и их изменения, Git применит объединенные изменения к снимку находится в коммите слияния . Полученные файлы могут быть зафиксированы автоматически, если нет конфликтов. Это действие по умолчанию для этих слияний; используйте --no-commit
для подавления этой фиксации по умолчанию.
Когда рекурсивная слияние использует внутреннее слияние для создания базовой фиксации слияния, она принудительно фиксирует результат , даже если существуют конфликты слияния . Вы не сможете увидеть, что он сделал с этими конфликтами, за исключением того, что появляется в базе слияний, когда ваше (внешнее) слияние также имеет конфликт. (В этом случае копия файла базы слияния доступна в слоте индекса 1. Кроме того, если вы установите merge.conflictStyle
на diff3
, каждая копия рабочего дерева конфликтующего файла будет отображать текст из базы слияния , в комплекте с маркерами конфликта.)