Я хочу знать точный алгоритм (или близкий к нему), стоящий за «git merge». По крайней мере, ответы на эти подвопросы будут полезны:
- Как git определяет контекст конкретного неконфликтного изменения?
- Как git обнаруживает конфликт именно в этих строках?
- Что делает git auto-merge?
- Как работает git, когда нет общей базы для слияния веток?
- Как работает git, когда есть несколько общих баз для слияния веток?
- Что произойдет, если я объединю сразу несколько веток?
- В чем разница между стратегиями слияния?
Но описание всего алгоритма будет намного лучше.
Ответы:
Возможно, вам лучше всего будет поискать описание алгоритма трехстороннего слияния. Описание высокого уровня будет выглядеть примерно так:
B
- версию файла, которая является предком обеих новых версий (X
иY
), и, как правило, самой последней такой базы (хотя бывают случаи, когда ей придется вернуться дальше, что является одним из особенностиgit
s по умолчаниюrecursive
слияния по )X
сB
иY
сB
.Полный алгоритм рассматривает это гораздо более подробно и даже имеет некоторую документацию ( https://github.com/git/git/blob/master/Documentation/technical/trivial-merge.txt , например, вместе со
git help XXX
страницами , где XXX является одним изmerge-base
,merge-file
,merge
,merge-one-file
и , возможно, некоторых других). Если этого недостаточно, всегда есть исходный код ...источник
Как работает git, когда есть несколько общих баз для слияния веток?
Эта статья была очень полезной: http://codicesoftware.blogspot.com/2011/09/merge-recursive-strategy.html (вот часть 2 ).
Рекурсивный рекурсивно использует diff3 для создания виртуальной ветви, которая будет использоваться в качестве предка.
Например:
Затем:
Есть 2 лучших общих предка (общие предки, которые не являются предками других),
C
иD
. Git объединяет их в новую виртуальную веткуV
, а затем используетV
в качестве основы.Я полагаю, Git просто продолжил бы, если бы было больше лучших общих предков, слияние
V
со следующим.В статье говорится, что если возникает конфликт слияния при создании виртуальной ветки, Git просто оставляет маркеры конфликта там, где они есть, и продолжает работу.
Что произойдет, если я объединю сразу несколько веток?
Как объяснил @Nevik Rehnel, это зависит от стратегии, это хорошо объясняется на
man git-merge
MERGE STRATEGIES
разделе.Только
octopus
иours
/theirs
поддерживает объединение нескольких веток одновременно,recursive
например, нет.octopus
отказывается от слияния, если будут конфликты, иours
это тривиальное слияние, поэтому конфликтов быть не может.Эти команды генерируют новую фиксацию, у которой будет более двух родителей.
Я сделал один
merge -X octopus
на Git 1.8.5 без конфликтов, чтобы посмотреть, как оно пойдет.Начальное состояние:
Действие:
Новое состояние:
Как и ожидалось,
E
имеет 3-х родителей.TODO: как именно осьминог работает с модификациями одного файла. Рекурсивное двухстороннее трехстороннее слияние?
Как работает git, когда нет общей базы для слияния веток?
@Torek упоминает, что с версии 2.9 слияние не выполняется без
--allow-unrelated-histories
.Я испытал это эмпирически на Git 1.8.5:
a
содержит:Затем:
a
содержит:Интерпретация:
a\nc\n
как добавление одной строки.источник
e379fdf34fee96cd205be83ff4e71699bdc32b18
), Git теперь отказывается выполнять слияние, если нет базы слияния, если вы не добавите--allow-unrelated-histories
.--allow-unrelated-histories
может быть опущено, если нет общих путей к файлам между объединяемыми ветвями.ours
стратегия слияния, но нетtheirs
стратегии слияния.recursive
+theirs
стратегия может разрешить только две ветви. git-scm.com/docs/git-merge#_merge_strategiesМне тоже интересно. Я не знаю ответа, но ...
Я думаю, что слияние git очень изощренно, и его будет очень трудно понять, но один из способов приблизиться к этому - использовать его предшественники и сосредоточиться на самой сути вашей заботы. То есть, учитывая два файла, у которых нет общего предка, как git merge определяет, как их объединить, и где возникают конфликты?
Попробуем найти предшественников. Откуда
git help merge-file
:Из википедии: http://en.wikipedia.org/wiki/Git_%28software%29 -> http://en.wikipedia.org/wiki/Three-way_merge#Three-way_merge -> http: //en.wikipedia .org / wiki / Diff3 -> http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf
Эта последняя ссылка представляет собой PDF-документ с
diff3
подробным описанием алгоритма. Вот версия для Google pdf-viewer . Это всего лишь 12 страниц, а алгоритм - всего пара страниц - но полная математическая обработка. Это может показаться слишком формальным, но если вы хотите понять слияние git, вам сначала нужно понять более простую версию. Я еще не проверял, но с таким именемdiff3
вам, вероятно, также понадобится понять diff (который использует самый длинный общий алгоритм подпоследовательности ). Однако может быть более интуитивное объяснениеdiff3
, если у вас есть Google ...Я просто провел эксперимент, сравнивая
diff3
иgit merge-file
. Они принимают одни и те же три входных файла version1 oldversion Version2 и оценка конфликтов То , как же, с<<<<<<< version1
,=======
,>>>>>>> version2
(diff3
также||||||| oldversion
), показывая их общее наследие.Я использовал пустой файл для oldversion , а также файлы почти одинаковые для version1 и version2 с добавлением только одна дополнительная линия Version2 .
Результат:
git merge-file
идентифицирована единственная измененная строка как конфликт; ноdiff3
рассматривал все два файла как конфликт. Таким образом, git merge, столь же сложный, как diff3, еще сложнее даже для этого простейшего случая.Вот фактические результаты (я использовал ответ @ twalberg для текста). Обратите внимание на необходимые параметры (см. Соответствующие страницы руководства).
$ git merge-file -p fun1.txt fun0.txt fun2.txt
$ diff3 -m fun1.txt fun0.txt fun2.txt
Если вам это действительно интересно, это что-то вроде кроличьей норы. Мне он кажется таким же глубоким, как регулярные выражения, самый длинный распространенный алгоритм подпоследовательности diff, контекстно-свободные грамматики или реляционная алгебра. Если вы хотите разобраться в этом, я думаю, вы сможете, но это потребует определенного исследования.
источник
Вот оригинальная реализация
http://git.kaarsemaker.net/git/blob/857f26d2f41e16170e48076758d974820af685ff/git-merge-recursive.py
По сути, вы создаете список общих предков для двух коммитов, а затем рекурсивно объединяете их, либо ускоренно пересылая их, либо создавая виртуальные коммиты, которые используются в качестве основы для трехстороннего слияния файлов.
источник
Если одна и та же строка изменилась с обеих сторон слияния, это конфликт; в противном случае принимается изменение с одной стороны (если таковое имеется).
Изменения, которые не конфликтуют (см. Выше)
По определению базы слияния Git существует только один (последний общий предок).
Это зависит от стратегии слияния (только стратегии
octopus
иours
/theirs
поддерживают слияние более двух веток).Это объясняется на
git merge
странице руководства .источник
git-merge-recursive
существует?git-merge-recursive
должно быть (страницы руководства нет, а Google ничего не дает). Более подробную информацию об этом можно найти на страницах руководстваgit merge
иgit merge-base
.git-merge
Страница людей иgit-merge-base
справочные страницы , которые вы отмечаете обсудить несколько общих предок и рекурсивное слияние. Я считаю, что ваш ответ будет неполным без такого обсуждения.