Почему git интерпретирует файлы sql как двоичные файлы во время конфликта слияния? - PullRequest
0 голосов
/ 25 августа 2018

У меня проблема с разрешением конфликтов слияния в файлах sql.

MenkeTTA@909086 MINGW64 //FILE0019 (master)
$ git pull
remote: Microsoft (R) Visual Studio (R) Team Services
remote: Found 5 objects to send. (5 ms)
Unpacking objects: 100% (5/5), done.
From https://***
d58a69b..4830c58  master     -> origin/master
warning: Cannot merge binary files: example_StoredProcedure.sql (HEAD vs.    4830c5886d3e1eac5ac76d1d49496afb43f444c3)
Auto-merging WRR - example_StoredProcedure.sql
CONFLICT (content): Merge conflict in example_StoredProcedure.sql 
Automatic merge failed; fix conflicts and then commit the result.

Когда создается конфликт слияния, git не создает предварительно объединенный файл с конкурирующими изменениями, как в обычной структуре:

/ SQL-File /

<<<<<<< HEAD
competing change A
=======
competing change B
>>>>>>> branch-a

Git рассматривает оба файла как двоичные файлы - но только для операций конфликта слияния (нормальное слияние без конфликта работает должным образом).Я могу выбрать свою собственную версию файла или извлеченный конкурирующий файл с пульта в качестве нового заголовка для следующего нажатия.

Я воспроизвел этот конфликт с помощью обычного файла .txt.Затем Git обрабатывает конфликт слияния, как и ожидалось, создавая один предварительно объединенный файл с обоими конкурирующими изменениями / коммитами, где я могу вручную исправить код так, как я хочу.

Чтобы git распознал файлы sql как текст I

.sql diff

добавлен в файл .gitattributes, как описано здесь .Кто-нибудь знает, как я могу сделать git для создания обычного предварительно объединенного файла с обеими версиями конкурирующих коммитов при работе с файлами sql?

1 Ответ

0 голосов
/ 25 августа 2018

Сначала короткое примечание:

Чтобы git распознал файлы sql как текст, я добавил

.sql diff

в файл .gitattributes ...

Строка .gitattributes должна читаться как *.sql diff (я исправил связанный ответ, который касается вопроса о том, как заставить git diff обработать файл как текст).Однако, если файл действительно является текстом, вам может потребоваться или даже понадобиться *.sql text.

Или, возможно, лучше: example_StoredProcedure.sql text, т. Е. Не all .sql файлов, только этот один конкретный файл.Мне также любопытно посмотреть, достаточно ли просто отметить его diff!

(Разница в том, что атрибут diff говорит Git, как показать файл в git diff выводе, 1 , в то время как text сообщает Git, что вместо использования встроенного алгоритма угадывания для всех целей следует использовать настройку, чтобы определить, является ли файл текстовым. Алгоритм угадывания состоит из сканированияначальный фрагмент содержимого файла, чтобы увидеть, сколько «текстоподобных» символов существует по сравнению с «нетекстовыми» символами. Вероятно, должно быть специальное значение для маркеров порядка байтов UTF-8 вверху, но нет . Любопытно, что во время фильтрации есть явные проверки .)


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


Более подробное объяснение

warning: Cannot merge binary files: example_StoredProcedure.sql (... vs ...)

говорит нам, что вы правы, что Git рассматривает три версии example_StoredProcedure.sql как двоичные.(Я вижу, вы добавили этот вывод после первоначального вопроса; хорошо, потому что это ключ!)

Но почему я сказал три версии, когда строка продолжает говорить:

HEAD vs.    4830c5886d3e1eac5ac76d1d49496afb43f444c3

Git немного ленив здесь: все слияния включают три входа, а не только два.Одним из них является тот, который вы предоставляете явно - или, как в этом случае, git pull run git merge и git pull сам предоставили большой некрасивый хэш-идентификатор 4830c5886d3e1eac5ac76d1d49496afb43f444c3.

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

Третий ввод - это то, что Git вычисляет для вас, основываясь на HEAD и других или --theirs коммитах: Git просматривает достаточное количество графов коммитов, чтобы найти лучший общийКоммит ancestor. 1 Именно этот третий вход - коммит общего предка - определяет , какие файлы нужно объединить , и если файл нуждается в объединении, встроенный драйвер слияния должен использовать diffчтобы получить текстовые изменения для слияния.Как для этого, так и для git diff, в Git встроен разностный движок (изменен с LibXDiff ).

Следовательно, Git, по сути, может работать:

git diff --find-renames <merge base commit> HEAD

чтобы увидеть, что мы сделали с каждым из наших файлов, и:

git diff --find-renames <merge base commit> <other commit>

, чтобы увидеть, что они сделали с каждым из наших файлов.Тогда:

  • Если мы изменили файл, а они его вообще не трогали, объединить легко: возьмите наш.

  • Если они изменили файл, а мы его вообще не трогали, объединить легко: взять их.

  • Если мы оба изменили файлно сделал новый файл точно таким же, объединение легко: взять любой (наш, действительно, так как он на месте).

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

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

Очевидно, что если Git не может преобразовать файл, он не может объединить два вывода diff.Но делает ли маркировка файла текстовым (<em>pattern</em> diff в .gitattributes) слияние?Что произойдет, если вы установите драйвер diff , использует ли этот код слияния низкоуровневый файл?Он «хочет» использовать внутренний интерфейс xdiff для поиска блоков;это намного проще, чем интерпретировать вывод текста из драйвера;вам, вероятно, придется определить драйвер слияния , чтобы получить обнаруженный как двоичный файл для слияния, даже если вы пометили его как diff.


1 Во всех случаях, но особенно в проблемных случаях, когда существует более одного лучшего общего предка, поведение git merge фактически зависит от выбранной вами стратегии .Обычная стратегия recursive объединяет базы слияния, фиксирует результат, а затем использует этот коммит в качестве базы слияния!Другие стратегии слияния работают иначе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...