Внутреннее слияние Git

Вероятно, это будет длинный вопрос, поэтому, пожалуйста, потерпите меня.

Я наткнулся на невероятное объяснение решений слияния git здесь: Как работает слияние git. Я пытаюсь основываться на этом объяснении и посмотреть, есть ли какие-либо пробелы в изображении git merge таким образом. По сути, решение о том, появится ли строка в объединенном файле, можно изобразить с помощью таблицы истинности:

W: исходный файл, A: ветка Алисы, B: ветка Боба

таблица правды

Основываясь на этой таблице истинности, легко придумать основанный на строках алгоритм построения D: построить D построчно, просматривая соответствующие строки из A и B и принимая решение на основе таблицы истинности.

Мой первый вопрос касается случая (0, 0, 1), который, согласно ссылке, которую я разместил выше, кажется, предполагает, что, хотя этот случай на самом деле является конфликтом, git обычно обрабатывает его, все равно удаляя строку. Может ли это дело когда-нибудь привести к конфликту?

Мой второй вопрос касается случаев удаления — (0, 1, 1) и (1, 0, 1). Интуитивно я чувствую, что то, как обрабатываются эти дела, может привести к проблеме. Допустим, в W была функция foo(). Эта функция никогда не вызывалась ни в одном фрагменте кода. Допустим, в ветке А Алиса наконец решила удалить foo(). Однако в ветке B Боб, наконец, решил использовать foo() и написал другую функцию bar(), которая вызывала foo(). Просто интуитивно, основываясь на таблице истинности, кажется, что объединенный файл в конечном итоге удалит функцию foo() и добавит bar(), а Боб останется недоумевать, почему foo() больше не работает! Что, вероятно, заставляет меня думать, что модель таблицы истинности, которую я вывел для трехстороннего слияния, вероятно, неполна и что-то упускает?


person Sandman    schedule 23.05.2015    source источник
comment
D — это объединенный коммит, верно?   -  person Nick Volynkin    schedule 23.05.2015


Ответы (2)


Мой первый вопрос в случае (0, 0, 1)

Некоторые системы контроля версий, такие как darcs, считают, что выполнение одного и того же изменения (в вашем случае удаления) в двух ветках и их слияние должно привести к конфликту. Типичный пример: дважды

-#define NUMBER_OF_WHATEVER 42
+#define NUMBER_OF_WHATEVER 43

Алгоритм слияния не может знать за вас, хотите ли вы, чтобы слияние давало 43 (поскольку это значение, с которым согласны обе версии) или 44 (поскольку 42 должно увеличиваться дважды).

Однако рассмотрение этого случая как конфликта порождает множество ложных конфликтов. Например, если кто-то выбирает слияние из ветки master в ветку сопровождения, а затем объединяет ветку сопровождения с master, то каждая строка, измененная при выборе вишни, приведет к конфликту. И маркеры конфликта были бы странными, потому что они показывали бы одно и то же содержимое по обе стороны от маркера конфликта, например

<<<<<<< HEAD
Hello world
=======
Hello world
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086

Таким образом, большинство систем контроля версий, включая Git, решили не рассматривать конфликт, когда обе стороны слияния вносят одно и то же изменение.

Мой второй вопрос касается случаев удаления — (0, 1, 1) и (1, 0, 1).

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

На практике они встречаются достаточно редко. Вероятно, миллионы людей ежедневно пользуются системой контроля версий и живут с ней. Большинство, вероятно, никогда не думало, что проблема может существовать.

Тем не менее, хорошая организация значительно снижает риск семантических конфликтов. Если вы проверите, что ваш код все еще компилируется после слияний, вы избежите примерно 90% семантических конфликтов, и если у вас есть автоматический набор тестов, вам придется найти семантические конфликты, которые создают ошибку, не покрываемую вашим набором тестов, чтобы он мог быть проблематичным.

И на самом деле семантические конфликты характерны не только для систем контроля версий. Другой сценарий, не использующий слияние,

  • Читаю код и вижу функцию f()
  • Мой коллега удаляет функцию f()
  • Работая над последней версией, в которой больше нет f(), я все еще помню, что есть функция f(), и пытаюсь ее использовать.

Словом, не бойтесь смысловых конфликтов.

person Matthieu Moy    schedule 23.05.2015
comment
Привет, Матье - спасибо за ваше время и отличный ответ. Итак, резюмируя ваш ответ на первый вопрос: (0, 0, 1) никогда не может привести к конфликту при слиянии двух ветвей, в то время как (1, 1, 0) может привести или не привести к конфликту в зависимости от того, является ли точный одна и та же строка была добавлена ​​​​с обеих сторон ветки (что в большинстве случаев никогда не происходит). Короче говоря, любые синтаксические конфликты (в отличие от семантических конфликтов, которые вы описываете) сводятся к случаю (1, 1, 0). Я прав, говоря это? - person Sandman; 24.05.2015
comment
Что касается вашего ответа на второй вопрос, почему вместо удаления отсутствующей строки для случаев (1, 0, 1) и (0, 1, 1) системы контроля версий просто не оставляют их. Итак, в по сути, вывод таблицы истинности для (1, 0, 1) и (0, 1, 1) будет 1, а не 0. Не позволит ли это избежать конкретного случая, который я набросал из вызова функций, которые были удалены в одной ветке, а не в другой? - person Sandman; 24.05.2015
comment
Потому что с вашим предложением вы не можете удалить часть кода. Удалите его, объедините, он вернется. Никто этого не хочет. - person Matthieu Moy; 24.05.2015

Вот пример репозитория, чтобы вы могли сами протестировать различные варианты поведения слияния. Он имеет множество веток с различными изменениями, которые сливаются друг с другом.

Не стесняйтесь разветвлять или клонировать его:

git clone https://github.com/NickVolynkin/GitMergeResearch.git

Скоро опубликую свои результаты.

введите здесь описание изображения

person Nick Volynkin    schedule 23.05.2015
comment
Привет, Ник. Спасибо, что нашли время и сделали репозиторий. Я также работал над локальным репозиторием, прежде чем сделать таблицу истинности выше. Нашли ли вы что-либо, противоречащее приведенной выше таблице? - person Sandman; 24.05.2015