Почему трехстороннее слияние выгоднее двухстороннего слияния?

165

Википедия говорит, что трехстороннее объединение менее подвержено ошибкам, чем двухстороннее, и часто не требует вмешательства пользователя. Почему это так?

Будет полезен пример, когда трехстороннее слияние завершается успешно, а двухстороннее слияние завершается неудачно.

Йоханнес Биттнер
источник

Ответы:

259

Допустим, вы и ваш друг извлекли файл и внесли в него некоторые изменения. Вы удалили строку в начале, а ваш друг добавил строку в конце. Затем он передал свой файл, и вам нужно объединить его изменения в вашу копию.

Если вы выполняли двустороннее слияние (другими словами, diff), инструмент мог сравнить два файла и увидеть, что первая и последняя строки различны. Но как он узнает, что делать с различиями? Должна ли объединенная версия включать первую строку? Должен ли он включать последнюю строку?

При трехстороннем слиянии он может сравнивать два файла, но также может сравнивать каждый из них с исходной копией (до того, как кто-либо из вас изменил ее). Таким образом, он может видеть, что вы удалили первую строку, а ваш друг добавил последнюю строку. И он может использовать эту информацию для создания объединенной версии.

JW.
источник
"Но как он узнает, что делать с различиями?" Не понял Если он уже может видеть различия между двумя файлами (без ссылки на оригинал), почему он не может применить оба изменения последовательно в возрастающем порядке временных меток файлов? То есть: он начинается с зарезервированной копии моего друга, которая принимает его за (новый) оригинал (с добавлением строки вверху), а затем, поверх него, применяет мои локальные изменения (удаление строки в нижней части).
Гарри
7
@ Гарри Скажи, у оригинала было три линии (ABC). Он начинается с копии моего друга (ABCD) и сравнивается с моим (BC). Не видя оригинала, можно подумать, что я удалил и A, и D, и что в конечном итоге должен быть BC.
JW.
80

Этот слайд из презентации перформанса интересен:

слайд-изображение

Основная логика трехстороннего инструмента слияния проста:

  • Сравните базовые, исходные и целевые файлы
  • Определите «чанки» в исходном и целевом файлах:
    • Куски, которые не соответствуют основанию
    • Куски, которые соответствуют основанию
  • Затем составьте объединенный результат, состоящий из:
    • Куски, которые соответствуют друг другу во всех 3 файлах
    • Куски, которые не соответствуют основанию ни в источнике, ни в цели, но не в обоих
    • Куски, которые не соответствуют основанию, но соответствуют друг другу (то есть они были одинаково изменены как в источнике, так и в цели)
    • Заполнители для блоков, которые конфликтуют, должны быть разрешены пользователем.

Обратите внимание, что «куски» на этой иллюстрации являются чисто символическими. Каждый из них может представлять строки в файле, узлы в иерархии или даже файлы в каталоге. Все зависит от того, на что способен конкретный инструмент слияния.

Вы можете спросить, какое преимущество предлагает трехстороннее слияние по сравнению с двухсторонним. На самом деле, не существует такой вещи, как двустороннее слияние, только инструменты, которые различают два файла и позволяют вам «объединять», выбирая фрагменты из одного файла или другого.
Только трехстороннее слияние дает вам возможность узнать, является ли чанк изменением от источника и конфликтует ли изменение.

VonC
источник
«конфликт изменений или нет». - не слияние с двух сторон (diff) также показывает конфликт (хотя информация теряется из-за источника конфликта) /
Влад
1
Однако в Git часто встречается слияние с 4 путями, когда база на самом деле не одинакова. Все же трехстороннее слияние лучше и двухстороннее.
Воскресенье,
@ Weernight, есть ли 5-стороннее слияние?
Pacerier
@Pacerier Не то, что я знаю, но это то, что на самом деле происходит во время git cherry-pick или rebase.
Воскресенье,
Очень подробное и полезное объяснение
Канег
20

Я написал очень подробный пост об этом . По сути, вы не можете отслеживать удаление / добавление с двухсторонней, очень, очень непродуктивной.

Пабло
источник
@pablo, если я добавлю функцию до X, а вы добавите другую функцию после X, и мы сделаем трехстороннее объединение, инструмент автоматически применит оба изменения. Но что происходит, когда мое изменение действительно вступает в конфликт с вашим изменением (например, каждый из нас создает новую функцию с тем же именем функции)? Как автоматическое слияние должно знать, что какое-то наше «скучное» слияние может вызвать конфликт ?
Пейсер
1
Просто прочитайте ваш урок, и он мне очень пригодится. Я чувствую то же самое, что и разработчики, которых вы описали. Я всегда боялся тройного слияния.
racl101
3
Я бы предложил вам скопировать и вставить часть вашей статьи. Я думаю, что это поможет вам получить положительные отзывы и будет в большей степени соответствовать философии stackoverflow.
Самуил
Хорошая статья Раньше мне нравилось использовать патчи для перебазирования, когда ты видишь больше контекста и можешь использовать свой редактор и среду для проверки чего-либо, хотя слишком много ручного манипулирования легкими вещами. Жаль, что нет хорошего способа, который бы сочетал в себе все хорошее
JonnyRaa
20

Трехстороннее объединение, при котором два набора изменений в один базовый файл объединяются по мере их применения, а не с применением одного, а затем объединяются с другим результатом.

Например, наличие двух изменений, в которых строка добавляется в одном и том же месте, может интерпретироваться как два добавления, а не как изменение одной строки.

Например

Файл a был изменен двумя людьми, один добавил лося, другой добавил мышь.

#File a
    dog
    cat

#diff b, a
    dog
+++ mouse
    cat

#diff c, a
    dog
+++ moose
    cat

Теперь, если мы объединяем наборы изменений при их применении, мы получим (объединение в 3 направления)

#diff b and c, a
    dog
+++ mouse
+++ moose
    cat

Но если мы применим b, то посмотрим на изменение с b на c, это будет выглядеть так, как будто мы просто меняем 'u' на 'o' (двухстороннее слияние)

    #diff b, c
    dog
--- mouse
+++ moose
    cat
Тео белэр
источник