A драйвер слияния , как определено в файле .gitattributes
, используется только тогда, когда все три входных файла различаются .
Это означает, что настройка merge=ours
( и определение драйвера слияния ours
) часто терпят неудачу. Я рекомендую не заморачиваться с этим: просто определите свой собственный процесс, с помощью которого вы будете их обрабатывать.
Подробнее
Прежде всего помните, что git merge
не всегда выполняет настоящее слияние:
-s
/ --squash
предписывает ему вообще не выполнять настоящее слияние, но он все равно будет использовать действие слияния как глагола (и запрещает перемотку вперед) .
--no-ff
запретит операцию быстрой перемотки вперед без слияния, в этом случае принудительное слияние будет выполнено.
--ff-only
вызовет сбой команды (и не слияние), если перемотка вперед без слияния невозможна.
Имейте это в виду при просмотре остальной части этого :
Здесь мы рассматриваем только стратегии разрешения и рекурсии; octopus merges и -s ours
совершенно разные.
Один из входных коммитов всегда HEAD
. Другой - коммит, который вы называете в командной строке. Команда git merge
сама найдет фиксацию базы слияния; это третья фиксация ввода. Если существует более одной фиксации базы слияния, -s resolve
выберет одну случайным образом, а -s recursive
сначала объединит базы слияния - это внутреннее рекурсивное слияние - а затем сделает новую фиксацию для использования в качестве базы слияния для внешнее слияние.
Если базовая фиксация слияния - это фиксация HEAD
, возможна перемотка вперед. Если разрешено, Git не будет выполнять слияние, а вместо этого просто проверит другой коммит, указанный в командной строке, настроив текущую ветвь так, чтобы он указывал на этот коммит.
Если базовая фиксация слияния - это другая фиксация, слияние не требуется: текущая ветка актуальна, и ничего не происходит.
Это оставляет реальные случаи слияния: задействованы три разных коммита . Каждый из этих коммитов имеет полный снимок любого количества файлов, и Git будет:
- сравнивать каждый файл в базе слияния с каждым файлом в
HEAD
, чтобы увидеть, что мы изменили; - сравните каждый файл в базе слияния с каждым файлом в другом коммите, чтобы увидеть, что они изменили; и
- объединяют эти изменения.
Чтобы объединить эти изменения, Git будет использовать низкоуровневый драйвер слияния . Это тип драйвера, который вы можете определить с помощью настройки merge=<em>name</em>
.gitattributes
. (Примечание: код рекурсивного / разрешающего слияния будет выполнять собственное высокоуровневое слияние для обработки вновь созданных файлов, удаленных и переименованных файлов, прежде чем перейти к низкоуровневому обработчику слияния. Это высокоуровневое слияние может привести к конфликт, который приведет к остановке слияния, независимо от того, что может делать низкоуровневый драйвер.)
Вот где возникает проблема: высокоуровневый код слияния, который обрабатывает любые высокоуровневые конфликты, вообще не беспокоится о запуске низкоуровневого кода слияния , если он может его пропустить. Этот высокоуровневый код пропускает низкоуровневый код всякий раз, когда необработанные идентификаторы ha sh объединяемых файлов совпадают в нескольких коммитах.
То есть, предположим, мы изменили файл F
и не сделали . Тогда ha sh из F
в базе слияния совпадает с ha sh из F
в их фиксации, но ha sh из F
в нашей фиксации отличается. Git предполагает, что правильное действие - взять наш файл: он никогда даже не запускает низкоуровневый драйвер слияния. С драйвером низкого уровня по умолчанию это нормально. С драйвером слияния ours
все еще нормально: Git взял наш F
.
Но предположим, что мы не изменили F
, а они сделали . Тогда ha sh из F
в базе слияния совпадает с ha sh из F
в нашем коммите, но не с ha sh в их. Git предполагает, что правильное действие - взять свой файл. Он никогда не запускает драйвер низкого уровня, даже если это драйвер слияния ours
.
Если Git имеет параметр .gitattributes
, который заставляет его запускать драйвер низкого уровня для каждого из них файлы, которые устранят проблему. Но это не так.