Я столкнулся со странным конфликтом слияния в файле .json, управляемом git, и понятия не имею, как это произошло.
Резюме: я добавил JSON-файл данных A.json в свою ветку A, а мой коллега добавил аналогичный отформатированный json-файл данных B.json в свою ветку B.
В обычном сценарии, когда я объединяю ветку B, нужно просто добавить B.json. До сих пор работало хорошо. Но сегодня git показал конфликт слияния с моим добавленным файлом A.json.
Мы уже проверили, что на ветке A нет файла B.json, а на ветке B нет файла A.json.
Вот скриншот этого конфликта:
Я подозреваю, что это может быть вызвано функцией git rename, но не уверен в этом.
Любая помощь будет оценена. Спасибо!
*Редактировать
Я запустил git diff для двух коммитов (фиксация при добавлении A.json и коммит при добавлении B.json) и подтвердил, что git обнаружил добавленные файлы как переименованные.
Но все же я не уверен, почему git обнаружил два разных добавления файлов при переименовании. Может быть, мне нужно больше узнать о функции переименования git...
@TimBiegeleisen «явно две версии одного и того же файла JSON» - Нет, это явно не две версии одного и того же файла json, это «индекс сходства 65%» разных сериализованных файлов json, которые git неправильно понял как переименованный файл. «Проверить историю двух веток», да, и может подтвердить, что это две разные коммиты добавления в разных двух файлах. Git каким-то образом обнаружил это добавление файла как переименование, я отредактирую свой вопрос с дополнительной информацией.
Я тоже думаю, что это из-за переименования файла. Вы можете проверить это самостоятельно:
git log -p -3 | grep -i 'renamed:'
...где -3
ограничивает количество коммитов в списке.
Git определяет переименование на основе содержимого файлов.
Спасибо за информацию, похоже, что переименование является причиной этого конфликта. После разрешения git, кажется, не регистрирует конфликтующие файлы как переименование, поэтому я запустил git diff и могу подтвердить, что git считает, что два файла переименованы.
Итак, здесь произошел немного сложный сценарий.
Во-первых, я нашел основную причину этого «переименования» с помощью команды
git merge --Xno-renames [branch_B]
Сценарий:
Мой коллега добавил B.json, и он был объединен с другой веткой. Я объединил эту другую ветку, поэтому B.json был добавлен в мою ветку без предварительного уведомления.
Во время автоматической очистки данных в моей ветке был удален B.json.
Я добавил A.json. Похоже, git подумал, что в этот момент B.json был переименован в A.json.
После этого, когда я объединяю ветку B, B.json создает конфликт с A.json.
Так что это не ошибка или проблема с переименованием git, это больше похоже на недостаток нашего рабочего процесса...
Механизм слияния Git основан на механизме обнаружения переименования Git.
Коммит Git хранит моментальный снимок каждого файла. Никакой лишней информации нет: есть только эти файлы. Так:
Если кто-то в какой-то момент добавит некоторый файл F, разница между старой фиксацией, в которой отсутствует файл F, и новой фиксацией, в которой есть файл F, будет содержать инструкцию: добавить новый файл с именем F с заданным содержимым.
Если кто-то удалит файл F и сделает новый коммит, то переход от старого коммита к новому включает инструкцию: удалить файл с именем F.
Если кто-то переименует файл F1 в новое имя F2, то сравнение между старым коммитом и новым говорит об удалении F1 и создании нового F2 с заданным содержимым.
В случае переименования это правильный способ получить правильный набор файлов: взять старый коммит, полностью удалить файл F1 и создать совершенно новый F2 с тем же содержимым, что и F1. Однако это длинная инструкция, и люди склонны возражать против нее: я не удалил файл, я его переименовал! Итак, git diff
имеет возможность проверить этот странный случай: файл F1 исчез, а на его месте появился файл F2. Возможно, это все-таки один и тот же файл.
Между тем, команда git merge
означает:
ours
изменения, это были.git merge
. Что бы ни изменилось, это работа, которую они сделали.Теперь предположим, что в общем базовом коммите есть файл с именем B.json
. В вашем собственном коммите есть файл с именем A.json
, но нет файла B.json
. Вы удалили B.json
и добавили совершенно новый и другой A.json
? Или вы переименовали существующий файл B.json
в A.json
и, возможно, немного изменили его?
Git не знает и не может знать, какое событие на самом деле произошло, но люди предпочитают, когда Git находит переименование, если два файла «достаточно похожи». Насколько похоже достаточно похоже? В Git есть метод вычисления индекса сходства между любыми двумя файлами. Функция diff-or-merge может сообщить вам, каким был индекс сходства — чтобы увидеть его с помощью git diff
самостоятельно, используйте git diff --find-renames
, чтобы убедиться, что вы вызываете детектор переименования, — и может сравнить его с некоторым пороговым значением. Пороговое значение по умолчанию — 50 %: файлы, похожие не менее чем на 50 %, считаются «одним и тем же файлом», даже если имя изменилось.
Флаг -X no-renames
полностью отключает обнаружение переименования. Флаг -X find-renames=value
устанавливает минимальный индекс сходства с заданным процентным значением (см. документацию для всех точных способов записи этого процента, но всегда работает двузначное число, поэтому вы можете использовать 99
для 99%, 50
для значения по умолчанию 50). % и 03
для 3%; имейте в виду, что 3
означает 30%).
Как вы только что видели, детектор переименования может дать осечку, найдя переименования, которых на самом деле никогда не было. Он также может не найти переименование, если было сохранено недостаточно исходного содержимого файла.
Спасибо за подробное объяснение!! Это очень помогло понять, что происходит под капотом!
Я имею в виду, что явно есть две версии одного и того же файла JSON, каждая из которых имеет разное значение ключа
"$id"
. Вы должны проверить историю двух ветвей, участвующих в слиянии, чтобы подтвердить это. Просто разрешите конфликт и двигайтесь дальше.