Git объединить внутренности
Возможно, это будет длинный вопрос, поэтому, пожалуйста, потерпите меня.
Я натолкнулся на невероятное объяснение решений git merge здесь: как работает git merge. Я пытаюсь опираться на это объяснение и посмотреть, есть ли какие-либо дыры в изображении git merge таким образом. По сути, решение о том, появляется ли строка в объединенном файле или нет, может быть отображено в таблице истинности:
W: исходный файл, A: ветвь Алисы, B: ветвь Боба
Основываясь на этой таблице истинности, легко придумать линейный алгоритм для построения D: Построить D построчно, посмотрев на соответствующие строки из A и B и приняв решение на основе таблицы истинности.
Мой первый вопрос - это случай (0, 0, 1), который согласно ссылке, которую я разместил выше, предполагает, что, хотя этот случай на самом деле является конфликтом, git обычно обрабатывает его, удаляя строку в любом случае. Может ли этот случай когда-либо привести к конфликту?
Мой второй вопрос о случаях удаления - (0, 1, 1) и (1, 0, 1). Интуитивно я чувствую, что способ обработки этих дел может привести к проблеме. Допустим, в W была функция was foo(). Эта функция никогда не вызывалась ни в одном фрагменте кода. Допустим, в ветке A Алиса наконец решила удалить foo(). Однако в ответвлении B Боб, наконец, решил использовать foo () и написал другую функцию bar(), которая вызвала foo(). Просто интуитивно, основываясь на таблице истинности, создается впечатление, что объединенный файл в конечном итоге удалит функцию foo () и добавит bar(), и Бобу будет интересно, почему foo () больше не работает! Что, вероятно, заставляет меня думать, что модель таблицы истинности, которую я получил для трехстороннего слияния, вероятно, не является полной и что-то упускает?
2 ответа
Мой первый вопрос - дело (0, 0, 1)
Некоторые системы контроля версий, такие как darcs, считают, что одно и то же изменение (в вашем случае удаление) в двух ветвях и объединение их должно привести к конфликту. Типичный пример, когда у вас есть дважды
-#define NUMBER_OF_WHATEVER 42
+#define NUMBER_OF_WHATEVER 43
Алгоритм слияния не может знать, хотите ли вы, чтобы слияние дало 43 (потому что это значение, с которым согласуются обе версии) или 44 (потому что 42 следует увеличивать в два раза).
Однако, рассматривая этот случай как конфликт, возникает много ложных конфликтов. Например, если кто-то выбирает слияние из основной ветки с ветвью сопровождения, а затем объединяет ветвь сопровождения с главной, то каждая строка, измененная с помощью черри, приведет к конфликту. И маркеры конфликта были бы странными, потому что они показывали бы одинаковый контент с обеих сторон маркера конфликта, например
<<<<<<< HEAD
Hello world
=======
Hello world
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086
Таким образом, большинство систем контроля версий, включая Git, решили не конфликтовать, когда обе стороны слияния вносят одно и то же изменение.
Мой второй вопрос о случаях удаления - (0, 1, 1) и (1, 0, 1).
То, что вы описываете, это семантические конфликты. Теоретически они существуют, и вы даже можете найти угловые случаи, когда объединение компилируется, но имеет другую семантику по сравнению с объединяемыми ветвями. В этом нет никакой магии, никакой текстовый алгоритм слияния не может обнаружить или разрешить семантические конфликты. Вы должны жить с ними или работать в одиночку.
На практике они достаточно редки. Вероятно, миллионы людей ежедневно пользуются системой контроля версий и живут с ней. Большинство, вероятно, никогда не думали, что проблема может существовать.
Тем не менее, хорошая организация значительно снижает риск семантических конфликтов. Если вы проверяете, что ваш код все еще компилируется после слияний, вы избегаете ~90% семантических конфликтов, и если у вас есть автоматический набор тестов, то вам нужно будет найти семантические конфликты, которые создают ошибку, не покрытую вашим тестовым набором, чтобы она могла быть проблематичным.
И на самом деле, семантические конфликты не являются специфическими для систем контроля версий. Другой сценарий, не использующий слияние:
- Я читаю код и вижу функцию
f()
- Мой коллега снимает функцию
f()
- Работа над последней версией, которой нет
f()
больше я до сих пор помню, что есть функцияf()
и я пытаюсь использовать это.
Короче говоря, не бойтесь семантических конфликтов.
Вот пример репозитория для вас, чтобы самостоятельно протестировать различные способы слияния. Он имеет множество веток с различными изменениями, чтобы сливаться друг с другом.
Не стесняйтесь раскошелиться или клонировать его:
git clone https://github.com/NickVolynkin/GitMergeResearch.git
Я скоро опубликую свои результаты.