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.