Когда бы вы использовали разные стратегии git merge?
На странице руководства git-merge есть несколько стратегий слияния, которые вы можете использовать.
разрешить - Это может разрешить только две головки (то есть текущую ветвь и другую ветвь, из которой вы извлекли), используя алгоритм трехстороннего слияния. Он пытается тщательно обнаружить неоднозначности слияния и считается в целом безопасным и быстрым.
рекурсивный - это может разрешить только две головы с использованием алгоритма 3-way merge. Если для трехстороннего слияния можно использовать несколько общих предков, оно создает объединенное дерево общих предков и использует его в качестве ссылочного дерева для трехстороннего слияния. Сообщается, что это приводит к меньшему количеству конфликтов слияния, не вызывая слияний в результате тестов, выполненных на реальных коммитах слияния, взятых из истории разработки ядра Linux 2.6. Кроме того, это может обнаруживать и обрабатывать слияния, связанные с переименованием. Это стратегия слияния по умолчанию при извлечении или слиянии одной ветви.
осьминог - это решает более чем двухголовый случай, но отказывается делать сложное слияние, которое требует ручного разрешения. Он в первую очередь предназначен для объединения глав веток тем. Это стратегия слияния по умолчанию при объединении или объединении нескольких веток.
ours - Это разрешает любое количество головок, но результатом слияния всегда является текущая головка. Он предназначен для замены старой истории развития боковых веток.
поддерево - это измененная рекурсивная стратегия. При объединении деревьев A и B, если B соответствует поддереву A, B сначала корректируется, чтобы соответствовать древовидной структуре A, вместо того, чтобы читать деревья на том же уровне. Эта корректировка также выполняется для общего дерева предков.
Когда я должен указать что-то отличное от значения по умолчанию? Для каких сценариев лучше всего подходит каждый?
3 ответа
Я не знаком с решимостью, но я использовал другие:
рекурсивный
Рекурсивный является значением по умолчанию для слияний без ускоренной пересылки. Мы все знакомы с этим.
Осьминог
Я использовал осьминога, когда у меня было несколько деревьев, которые нужно было объединить. Вы видите это в более крупных проектах, где многие филиалы имели независимое развитие, и все они готовы объединиться в одну голову.
Ветвь осьминога объединяет несколько голов в один коммит, если он может делать это чисто.
Для иллюстрации представьте, что у вас есть проект с мастером, а затем три ветви для объединения (назовите их a, b и c).
Серия рекурсивных слияний будет выглядеть следующим образом (обратите внимание, что первое слияние было ускоренным, так как я не вызывал рекурсию):
Тем не менее, одиночное слияние осьминога будет выглядеть так:
commit ae632e99ba0ccd0e9e06d09e8647659220d043b9
Merge: f51262e... c9ce629... aa0f25d...
наш
Наша == Я хочу добавить другую голову, но выбросить все изменения, которые вносит эта голова.
Это сохраняет историю ветви без каких-либо эффектов ветви.
(Читайте: это даже не рассматривало изменения между этими ветвями. Ветви просто слиты, и ничего не делается с файлами. Если вы хотите объединить в другую ветку, и каждый раз возникает вопрос "наша версия файла или их версия "вы можете использовать git merge -X ours
)
Subtree
Поддерево полезно, когда вы хотите объединить другой проект с подкаталогом вашего текущего проекта. Полезно, когда у вас есть библиотека, которую вы не хотите включать в качестве подмодуля.
На самом деле единственными двумя стратегиями, которые вы хотели бы выбрать, являются наши, если вы хотите отказаться от изменений, внесенных ветвью, но сохранить ветку в истории и поддерево, если вы объединяете независимый проект в подкаталог суперпроекта (например, "git-gui" in "). Git 'хранилище).
объединениеосьминога используется автоматически при объединении более двух ветвей. Решение здесь в основном по историческим причинам, а также для случаев, когда вы сталкиваетесь с угловыми случаями стратегии рекурсивного объединения.
"Решить" против "Рекурсивной" стратегии слияния
Рекурсивная является текущей стратегией с двумя головками по умолчанию, но после некоторого поиска я наконец нашел некоторую информацию о стратегии слияния "решить".
Взято из книги О'Рейли Контроль версий с помощью Git ( Amazon) (перефразировано):
Первоначально, "разрешение" было стратегией по умолчанию для слияний Git.
В ситуациях перекрестного слияния, когда существует более одной возможной базы слияния, стратегия разрешения работает следующим образом: выберите одну из возможных баз слияния и надейтесь на лучшее. Это на самом деле не так плохо, как кажется. Часто оказывается, что пользователи работают над разными частями кода. В этом случае Git обнаруживает, что он повторно объединяет некоторые уже внесенные изменения, и пропускает повторяющиеся изменения, избегая конфликта. Или, если это небольшие изменения, которые вызывают конфликт, по крайней мере, конфликт должен быть легким для разработчика.
Я успешно объединил деревья, используя "resolv", который не удался с рекурсивной стратегией по умолчанию. Я получал fatal: git write-tree failed to write a tree
ошибки, и благодаря этому сообщению в блоге ( зеркало) я попытался "-с разрешить", который работал. Я все еще не совсем уверен, почему... но я думаю, что это произошло потому, что у меня были дублирующие изменения в обоих деревьях, и я решил, что "пропустил" их правильно.
В Git 2.30 (первый квартал 2021 г.) будет новая стратегия слияния: ORT ("якобы рекурсивный близнец").
git merge -s ort
См. Фиксацию 14c4586 (2 ноября 2020 г.), фиксацию fe1a21d (29 октября 2020 г.) и фиксацию 47b1e89, фиксацию 17e5574 (27 октября 2020 г.) Элайджа Ньюрен (newren
).
(Слияние Junio C Hamano -
gitster
- в коммите a1f9595, 18 ноя 2020)
merge-ort
: barebones API новой стратегии слияния с пустой реализациейПодписано: Элайджа Ньюрен
Это начало новой стратегии слияния.
Хотя есть некоторые различия API, а реализация имеет некоторые отличия в поведении, по сути, это подразумевается как возможная замена для
merge-recursive.c
.Тем не менее, он строится так, чтобы существовать бок о бок с рекурсивным слиянием, так что у нас есть достаточно времени, чтобы узнать, как эти различия проявляются в реальном мире, в то время как люди все еще могут вернуться к рекурсивному слиянию.
(Кроме того, я намерен избегать изменения рекурсивного слияния во время этого процесса, чтобы он оставался стабильным.)Основное заметное отличие заключается в том, что обновление рабочего дерева и индекса не выполняется одновременно с алгоритмом слияния, а представляет собой отдельный этап постобработки.
Новый API спроектирован так, чтобы можно было выполнять многократные слияния (например, во время перебазирования или выбора вишни) и обновлять индекс и рабочее дерево только один раз в конце, а не обновлять его с каждым промежуточным результатом.Кроме того, можно выполнить слияние двух ветвей, ни одна из которых не соответствует ни индексу, ни рабочему дереву, не повреждая индекс или рабочее дерево.
И:
См. Commit 848a856, commit fd15863, commit 23bef2e, commit c8c35f6, commit c12d1f2, commit 727c75b, commit 489c85f, commit ef52778, commit f06481f (26 Oct 2020) Элайджа Ньюрен (newren
).
(Слияние Junio C Hamano -
gitster
- в коммите 66c62ea, 18 ноя 2020)
t6423, t6436
: обратите внимание на улучшенную обработку орт с грязными файламиПодписано: Элайджа Ньюрен
"Рекурсивный" бэкэнд полагается на
unpack_trees()
чтобы проверить, будут ли неустановленные изменения перезаписаны слиянием, ноunpack_trees()
не понимает переименований - и как только он возвращается, он уже написал много обновлений для рабочего дерева и индекса.
Таким образом, "рекурсивный" должен был выполнить специальное 4-стороннее слияние, при котором рабочая копия также должна была бы рассматриваться как дополнительный источник различий, которые мы должны были тщательно избегать перезаписи и приводили к перемещению файлов в новые места, чтобы избежать конфликтов.Бэкэнд "ort", напротив, выполняет полное слияние в памяти и обновляет только индекс и рабочую копию на этапе постобработки.
Если на пути есть грязные файлы, он может просто прервать слияние.
t6423
: ожидайте улучшенных меток маркеров конфликтов в бэкэнде ortПодписано: Элайджа Ньюрен
Маркеры конфликтов содержат дополнительную аннотацию в виде REF-OR-COMMIT:FILENAME, чтобы помочь различить, откуда поступает контент, с
:FILENAME
кусок будет опущен, если он одинаков для обеих сторон истории (таким образом, только переименования с конфликтами содержимого несут эту часть аннотации).Однако были случаи, когда
:FILENAME
аннотация была случайно отключена из-за формата слияния-рекурсии для каждого-кода-пути-требуется-копия-всего-особого-кода-кода.
t6404, t6423
: ожидайте улучшенной обработки переименования / удаления в бэкэнде ortПодписано: Элайджа Ньюрен
Когда файл переименован и имеет конфликты содержимого, рекурсивное слияние не имеет некоторых этапов для старого имени файла и некоторых этапов для нового имени файла в индексе; вместо этого он копирует все этапы, соответствующие старому имени файла, в соответствующие места для нового имени файла, так что есть три этапа более высокого порядка, все соответствующие новому имени файла.
Такой подход упрощает пользователю доступ к различным версиям и разрешение конфликта (нет необходимости вручную
git rm
'(человек) старая версия, а также'git add
'(мужчина) новый).переименование / удаление должны обрабатываться аналогично - для переименованного файла должно быть два этапа, а не только один.
Мы не хотим прямо сейчас дестабилизировать рекурсивное слияние, поэтому вместо этого обновите соответствующие тесты, чтобы они имели разные ожидания в зависимости от того,recursive
" или же "ort
"используются стратегии слияния.
С Git 2.30 (первый квартал 2021 г.), подготовка к новой стратегии слияния.
См. Commit 848a856, commit fd15863, commit 23bef2e, commit c8c35f6, commit c12d1f2, commit 727c75b, commit 489c85f, commit ef52778, commit f06481f (26 Oct 2020) Элайджа Ньюрен (newren
).
(Слияние Junio C Hamano -
gitster
- в коммите 66c62ea, 18 ноя 2020)
merge tests
: ожидайте улучшения обработки конфликтов каталогов / файлов в ortПодписано: Элайджа Ньюрен
merge-recursive.c
построен на идее бегаunpack_trees()
а затем "мелкие поправки" для получения результата.
К сожалению,unpack_trees()
был запущен в режиме обновления по мере продвижения,merge-recursive.c
чтобы последовать их примеру и в итоге получить немедленную оценку и готовый дизайн.Некоторые вещи, такие как конфликты каталогов / файлов, плохо представлены в структуре данных индекса, и для их обработки требуется специальный дополнительный код.
Но затем, когда было обнаружено, что конфликты переименования / удаления также могут быть вовлечены в конфликты каталогов / файлов, специальный код обработки конфликтов каталогов / файлов пришлось скопировать в путь кода переименования / удаления.
... а затем его нужно было скопировать для изменения / удаления и для конфликтов переименования / переименования (1to2)... и все же он все еще пропустил некоторые.
Кроме того, когда было обнаружено, что также существуют конфликты файлов / подмодулей и конфликты подмодулей / каталогов, нам нужно было скопировать специальный код обработки подмодулей во все особые случаи всей кодовой базы.А затем было обнаружено, что наша обработка конфликтов каталогов / файлов была неоптимальной, потому что она создавала неотслеживаемые файлы для хранения содержимого конфликтующего файла, которое не было бы очищено, если бы кто-то запустил '
git merge --abort
'(мужчина) или'git rebase --abort
'(мужчина).Также было сложно или страшно пытаться добавить или удалить записи индекса, соответствующие этим файлам, из-за конфликта каталогов / файлов в индексе.
Но изменениеmerge-recursive.c
правильно обрабатывать их было королевской болью, потому что в коде было так много сайтов с похожим, но не идентичным кодом для обработки конфликтов каталогов / файлов / подмодулей, которые все должны были быть обновлены.Я усердно работал над тем, чтобы протолкнуть всю обработку конфликтов каталогов / файлов / подмодулей в слиянии через один путь кода и избежать создания неотслеживаемых файлов для хранения отслеживаемого контента (он записывает вещи по альтернативным путям, но следит за тем, чтобы они имели этапы более высокого порядка в индексе).
Поскольку ответы выше не показывают всех деталей стратегии. Например, в каком-то ответе отсутствуют сведения об импортеresolve
вариант и recursive
который имеет много дополнительных опций, таких как ours
, theirs
, patience
, renormalize
, так далее.
Поэтому рекомендую посетить официальный git
документация, которая объясняет все возможные функции: