git опции стратегии рекурсивного слияния в .gitattributes - PullRequest
0 голосов
/ 22 ноября 2018

Я борюсь с принудительным определением стратегии слияния (-s recursive -Xours) для определенных файлов в файле .gitattributes в Git.

Я играл с файлами .git / config и .gitattributes безУспех, что мне удалось до сих пор, не учитывает параметр -X.

.gitattributes

*pom.xml merge=recursive

.git / config

[merge "recursive"]
  driver = true

1 Ответ

0 голосов
/ 23 ноября 2018

TL; DR

Используйте git merge-file в вашем драйвере слияния.Здесь вы можете указать нужные параметры.Вы просите --ours.Имейте в виду, что это не всегда работает правильно.Возможно, вы даже захотите --union, но имейте в виду, что это на самом деле тоже не работает.См. Можно ли сделать git главным образом с автоматическим слиянием нечувствительных к порядку файлов XML? и VS 2013 C # и Git: файлы .csproj не объединяются при извлечении из-за проблем с попыткой использованиялюбой метод с файлами XML.

Long

Сначала давайте определим термины, как Git использует их:

  • A стратегия - это аргумент, который вы передаете флагу -s git merge: git merge -s recursive, git merge -s resolve, git merge -s ours или git merge -s octopus.(На практике вы никогда бы не использовали последний явно - вместо этого это подразумевается, если вы попросите Git объединить несколько голов.)

    Другими словами, это одно из имен ours, recursive,или resolve.Теоретически, вы можете написать свою собственную стратегию слияния Git, но это очень нетривиально (настолько, что я не слышал, чтобы кто-то делал это, хотя это может не так много значить).

  • A опция стратегии аргумент, который вы передаете флагу -X, например -X ours или -X rename-threshold=<number>.Я считаю, что это плохое имя, так как его слишком легко спутать со стратегией .Это особенно верно, когда вы говорите: вы сказали «стратегия», а затем перестали говорить, но имели в виду «вариант стратегии», и вас просто прервали, или вы сказали «стратегия» и перестали говорить и на самом деле имели в виду «стратегия»?Мне нравится называть эти расширенные опции , что хорошо сочетается с флагом -X, который затем обозначается как «eXtended».)

  • A драйвер - это то, что вы определяете в файле .gitattributes.Существует несколько разновидностей (filter, diff и merge);здесь мы имеем дело с драйверами слияния.Драйверы слияния вызываются стратегией ;теоретически, драйвер может иметь доступ по крайней мере к некоторым расширенных опций, но на практике они этого не делают.(Git должен определять % -экспандеры, которые предоставляют их и / или предоставляют их в переменной окружения; это было бы относительно просто.)

С этими определениями легкочтобы увидеть, что это:

Я борюсь с форсированием определенной стратегии слияния (-s recursive -Xours) для определенных файлов в файле .gitattributes Git.

буквальноневозможно.Это верно, если вы имеете в виду стратегии или опции стратегии здесь: оба были выбраны задолго до того, как мы перейдем к драйверу слияния , определенному в файле .gitattributes.

Все не обязательно потеряно, хотя!

Вы упомянули конкретно pom.xml, для которого вам нужен драйвер слияния - то, что вы можете определить в .gitattributes - то есть слияние стиля текстано берет «наш», если есть конфликт, а-ля расширенный вариант «наш».Вместо этого у вас есть драйвер слияния, который будет выполнять «нашу» стратегию слияния: полностью игнорировать и базу слияния, и их изменения, просто взяв «нашу» версию файла.

Сравните вашу попытку с ответом на Как правильно использовать .gitattributes с merge = ours : единственная разница - это написание имени драйвера, где вы используете recursive вместо ours.Имя драйвера не важно, если это не одно из известных магических имен (text, binary и union): Git будет запускать ваш драйвер вместо того, чтобы выполнять свое собственное слияние на уровне файлов,когда он определяет, что должно быть выполнено слияние на уровне файлов.

Документация gitattributes может сказать об определении драйвера слияния:

определение драйвера слияния выполняется в файле .git/config, а не в файле gitattributes, поэтому, строго говоря, эта страница руководства не подходит для разговоров об этом.Однако ...

Чтобы определить пользовательский драйвер слияния filfre, добавьте раздел в файл $GIT_DIR/config (или $HOME/.gitconfig файл), например:

[merge "filfre"]
    name = feel-free merge driver
    driver = filfre %O %A %B %L %P
    recursive = binary

(Примечание: рекурсивный = двоичный файл не обязательно является хорошим советом, но давайте сейчас нажмем здесь.)

Переменная merge.*.name дает драйверу удобочитаемое имя.

Значение переменной merge.*.driver используется для создания команды, которая будет выполняться для объединения версии предка (%O), текущей версии (%A) и версии других ветвей (%B).Эти три токена заменяются именами временных файлов, которые содержат содержимое этих версий при сборке командной строки.Кроме того, %L будет заменен размером маркера конфликта (см. Ниже).

То есть %O называет временный файл, содержащий версию файла на основе слияния, а %A и %B называют временные файлы, содержащие версии --ours и --theirs файла.Ваша задача как создателя фильтра-драйвера - создать команду, которая будет выполнять слияние:

Ожидается, что драйвер слияния оставит результат слияния в файле с именем %A, перезаписав его, и выйдите с нулевым статусом, если ему удалось объединить их чисто, или ненулевым, если были конфликты.

Выполнив объединение, вы должны перезаписать %A названный файл с результатом.Поскольку файл с именем %A содержит содержимое --ours, драйвер, который ничего не делает, но затем завершает работу, объявляет, что правильное содержимое для объединения %O против %A и %B - это то, что уже в %A.

Другими словами, это похоже на нашу стратегию .Это не то же самое, что стратегия «плюс плюс» с опцией «слияние в случае конфликтов», вариант «решай или рекурсивно с -Xours».Но вам не нужна целая стратегия , так как это касается целых коммитов;Вы хотите один файл операция.Вот где приходит git merge-file. Давайте закончим остальное описание сейчас, хотя:

Переменная merge.*.recursive указывает, какой другой драйвер слияния использовать, когда драйвер слияния вызывается длявнутреннее слияние общих предков, когда их больше одного.Если этот параметр не указан, сам драйвер используется как для внутреннего слияния, так и для окончательного слияния.

Это немного сбивает с толку, но применяется только к рекурсивной стратегии и дажетогда, только если git merge-base --all HEAD <theirs> печатает несколько хеш-идентификаторов.В большинстве случаев здесь вам не нужно ничего особенного.Использование recursive = binary эквивалентно установке для этого одного файла стратегии resolve, поскольку внутренний драйвер слияния binary просто принимает версию ours, что означает, что когда -s recursive многократно объединяет базы слияния, онпросто каждый раз возвращает первую базовую версию слияния.

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

Драйвер слияния может узнать путь, в котором объединенный результат будет сохранен через заполнитель%P.

Более конкретно, ваш драйвер будет вызываться с расширением %A, например, .mergetmpA12345, %B с расширением до .mergetmpB12345 и %O с расширением до .mergetmpO12345.Это верно независимо от того, вызывается ли вам слияние трех копий README.txt, трех копий main.py или трех копий pom.xml: временные имена файлов будут .merge<something>.

Если вы хотите, по какой-либо причине, узнать, что «настоящее имя» файла - README.txt или main.py или что-то еще, , что доступно в %P. не используйте этот файл сейчас - это не вход и не выход.Это просто конечное имя файла рабочего дерева - это или будет его (окончательное) имя , как только слияние будет завершено.На данный момент, однако, имя, которое вы должны использовать - то, куда вы должны доставить данные объединенного файла, - это то, что %A расширяется до (некоторые .merge<something>).

Используя git merge-file

Документация git merge-file сообщает нам, что git merge-file используется для:

git merge-file [-L <current-name> [-L <base-name> [-L <other-name>]]] [--ours |--theirs |--union] [-p |--stdout] [-q |--quiet] [--marker-size=<n>] [-- [no-] diff3] <current-file> <base-file> <other-file>

Три варианта -L: метки , которые git merge-file разместит вокруг конфликтующих разделов.Опция --marker-size устанавливает размер маркера, который git merge-file будет размещать вокруг конфликтующих участков.Значения по умолчанию очень похожи на собственное внутреннее слияние Git, поэтому в большинстве случаев они не нужны.В вашем случае вы собираетесь указать --ours, что означает , что никогда не будет неразрешенных конфликтов , и поэтому -L и --marker-size не нужны.

* 1254Флаг * или --theirs или --union указывает git merge-file, как обрабатывать конфликты.Два из этих флагов такие же, как расширенные опции -X ours и -X theirs;вы получаете третий, который недоступен при обычном Git-слиянии.

Параметры --diff3 или --no-diff3 снова влияют на отображение конфликтов: они эквивалентны установке merge.style в diff3 или merge соответственно.Поскольку у вас не будет конфликтов, это не имеет значения.

Наконец, вам нужно назвать три файла: один, содержащий данные текущей ("нашей") версии, один с базовой версией слияния и один сдругая ("их") версия.Когда git merge-file завершится, он перезапишет файл текущей версии с объединенными данными.Ваш git merge, удобно, построил три таких файла и использует их именно таким образом, поэтому вам нужно только указать опции %A %O %B:

*pom.xml merge=favor-ours

и:

[merge "favor-ours"]
    name = merge driver that merges but favors ours a la -X ours
    driver = git merge-file --ours %A %O %B

Из-за опции --ours это объединение всегда будет успешным (git merge-file будет выходить из 0), даже если результат не является допустимым XML.

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