Конфликт слияния Git. Что значит «изменить одну и ту же часть одного и того же файла по-разному»?

Глава 3.2 книги Git указывает:

…Occasionally, this process doesn’t go smoothly. If you changed the same part of the same file differently in the two branches you’re merging, Git won’t be able to merge them cleanly.…

Как следует интерпретировать неоднозначное выражение «изменить одну и ту же часть одного и того же файла по-разному»? Выполняет ли Git внутреннее сравнение строк за строкой в ​​конфликтующем файле между ветвями?


Пример:

Предположим, в ветке л я добавляю дополнительную новую строку в начале README.md. Означает ли это, что изменение любой строки, отличной от первой, в README.md в другой ветке р вызовет конфликт при слиянии?

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

Как это двусмысленно? И да, довольно много.

Ry- 10.04.2019 23:49

Добавлен пример для дальнейшего объяснения.

Simón Ramírez Amaya 11.04.2019 00:03

«…вызовет конфликт при слиянии?» Нет, потому что это будет другая часть того же файла. В книге сказано «та же часть того же файла».

Ry- 11.04.2019 00:05

«Вы ожидаете, что наивное построчное сравнение потерпит неудачу…» Сравнение Git не так уж и наивно.

Code-Apprentice 11.04.2019 00:07

@Code-Apprentice Именно поэтому я задаю вопрос. Чем отличается Git от наивности?

Simón Ramírez Amaya 11.04.2019 00:09
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
5
939
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Помните, что Git делает не одну, а два диффов:

  • есть база слияния Б с некоторыми файлами,
  • и левый коммит л с некоторыми файлами,
  • и правый коммит р с некоторыми файлами.

База слияния Б одинакова в командах обеgit diff:

git diff --find-renames <hash-of-B> <hash-of-L>    # what we changed
git diff --find-renames <hash-of-B> <hash-of-R>    # what they changed

Итак, предположим, что мы и они оба модифицировали файл F.ext. Из первый diff видно, какие строки F.extмы изменились: те, которые перечислены как удаленные в фрагменте diff относительно B, плюс еще одна «промежуточная» линия на краю для безопасности — край идет вперед, поэтому, если мы заменили исходную строку 3 мы «тронули» строки 3 и «3 с половиной». Если бы мы не удалили ни одной строки — если бы мы вставили строку после строки 3 перед строкой 4 — тогда мы коснулись строки «3 с половиной».

Между тем, из разницы второй также видно, какие строки F.extOни изменились. Применяются те же правила: если они заменили исходную строку 3 новой строкой 3, то они коснулись строки 3 (включая строку «3.5»). Итак, если мы коснулись строки 3 или строки 3.5, возник конфликт. В противном случае конфликта нет: Git может просто принять изменение от той стороны, которая внесла изменение в рассматриваемую строку (строки).

(Обратите внимание, что git diff представляет разницу как разницу контекста единый. В коде слияния используется необработанная, неунифицированная разница. Поэтому в нем есть список, который гласит: «в строке Икс оригинала удалите строки Д и вставьте новые строки замены я», где не более одного из Д или я может быть нулем. Коснувшийся отрезок - это линия Икс через линию Х + Д + 0,5, более или менее. Со своим странным "плюсом на половину" я действительно просто энергично машу руками, чтобы прикрыть пустой пролет проблема, которая является является проблемой. Вам придется поэкспериментировать с Git, чтобы увидеть, что именно он делает в каждом случае.)

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

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

Когда вы начинали, у вас была точно такая же версия, что и у Боба. Но поскольку вы работаете независимо, легко увидеть, что вы и Боб можете изменять файл ПРОЧТИ МЕНЯ одновременно. Возможно, вы заметили, что в первом предложении есть слово с ошибкой, и исправили его. Тем временем Боб решает, что введение сбивает с толку, поэтому переписывает первые два абзаца. В версии Боба опечатка осталась, но теперь она находится в другой строке.

Итак, между вашей версией и версией файла README Боба есть конфликт. Когда вы с Бобом решите объединить свои изменения вместе, git merge обнаружит этот конфликт и отправит вам жалобу. Вы не хотите, чтобы слияние отбросило ваши изменения, так как Боб не заметил орфографическую ошибку. Но вы также не хотите выбрасывать работу Боба. Следовательно, решение об объединении изменений из вашего README и README Боба должно приниматься человеком.

В данном случае вы с Бобом изменили одну и ту же строку README. Но что, если бы вы коснулись разных линий? В качестве меры предосторожности git merge по-прежнему будет жаловаться, если ваши измененные строки достаточно близки к измененным строкам Боба, потому что все еще может возникнуть конфликт.

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

Другие вопросы по теме