Git - как вызвать конфликт слияния и ручное слияние для выбранного файла

83

Мы поддерживаем веб-приложение, которое имеет общую главную ветвь и множество параллельных ветвей, по одной для каждой установки, каждая из которых имеет несколько конкретных изменений. Исходный код управляется в git, и это отличный инструмент, когда нам нужно перенести функции и исправления из основной ветки в параллельные. Но мало файлов, которые являются конфиденциальными, и автоматическое слияние обычно дает плохие результаты. Таким образом, слияние было бы намного проще, если бы их можно было как-то пометить, и каждое слияние привело бы к конфликту, требующему слияния вручную.

Я искал ответ:

  1. Я использую параметры слияния --no-commit и --no-ff , но это не одно и то же.
  2. Здесь и здесь кто-то задает тот же вопрос, но без решения.
  3. Похожий случай, похоже, заключается в том, как предотвратить слияние файлов с использованием .gitattributes, содержащих: somefile.php merge = ours . Я попытался найти какой-нибудь вариант слияния, который мог бы вызвать конфликт или принудительное слияние вручную, но пока не нашел.
  4. .gitattributes, содержащие: somefile.php -merge , никогда не объединяются автоматически, поэтому принудительное объединение выполняется вручную. Это 90% -ное решение, но я стремлюсь попробовать автоматическое слияние и пометить его как конфликт независимо от того, успешно оно или нет.Но это пока что ближе всего к решению. (... спасибо Чарльзу Бейли за разъяснения ...)
  5. Кто-то предлагает написать собственный драйвер слияния ( 1 , 2 ), но как это сделать, мне далеко не ясно.

редактировать: вариант 4. описание

Степан
источник
6
Это не будет точный ответ, который вы ищете, но по той же причине, по которой я git fetchсначала делаю , а затем использую git difftool <file> FETCH_HEAD, поэтому я могу вручную применить изменение в удаленной ветке к локальному.
MHC
MHC: это хороший трюк (особенно если он сохраняется в скрипте для каждой параллельной ветки + в сочетании с предотвращением автоматического слияния файлов). Главный недостаток состоит в том, что в командном рабочем процессе есть вероятность, что кто-то забудет этот шаг и вместо этого просто выполнит обычное слияние.
Степан
2
Настройка -mergeне мешает вам объединять файлы, она просто заставляет вас делать это вручную, например, с помощью mergetool. Разве это не то, что тебе нужно?
CB Bailey,
Это 90% того, что я хочу. Я бы хотел, чтобы слияние выполнялось автоматически, но для этого конфиденциального файла слияние считается конфликтом, даже если его нет, поэтому ручная проверка выполняется каждый раз принудительно.
Степан
@Stepan У меня похожая ситуация, поэтому я хочу кое-что прояснить. Что вы говорите о том, что -mergein .gitatttributes git mergeничего не делает, и вся работа должна быть прекращена с помощью инструмента слияния? Итак, нет <<<<< ===== >>>> для использования инструмента слияния, верно? И решение Дэна это обеспечивает?
Nero gris

Ответы:

60

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

Сначала создайте сценарий драйвера слияния с именем merge-and-verify-driver. Сделайте его исполняемым и поместите в подходящее место (вы можете рассмотреть возможность проверки этого скрипта в репо, даже если от него будет зависеть конфигурационный файл репо). Git выполнит этот сценарий оболочки, чтобы выполнить слияние конфиденциальных файлов:

#!/bin/bash
git merge-file "${1}" "${2}" "${3}"
exit 1

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

Затем вам нужно сообщить Git о существовании вашего настраиваемого драйвера слияния. Вы делаете это в файле конфигурации репозитория ( .git/config):

[merge "verify"]
        name = merge and verify driver
        driver = ./merge-and-verify-driver %A %O %B

В этом примере я поместил merge-and-verify-driverкаталог верхнего уровня репо ( ./). Вам нужно будет указать путь к сценарию соответственно.

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

*.sensitive merge=verify

Здесь я сказал Git, что любой файл с именем, соответствующим шаблону, *.sensitiveдолжен использовать специальный драйвер слияния. Очевидно, вам нужно использовать шаблон, подходящий для вашего файла (ов).

Дэн Молдинг
источник
Большое спасибо за это подробное руководство!
Степан
13
Похоже, что драйвер слияния не вызывается в «очевидных» решениях. Например, если файл был изменен только в одной ветке, и вы выполняете слияние, «чувствительный» файл будет перезаписан, и драйвер слияния не будет вызван. Есть способ исправить это?
VitalyB 09
Будет ли это вести себя так, как предлагает @VitalyB? благодаря!
filippo 06
1
Это работает, но есть ли способ сделать это глобальным параметром для всех репозиториев на машине? Кроме того, есть ли способ вызвать его из командной строки? Я бы хотел, чтобы это было так просто, как изменение стратегии слияния в командной строке.
user1748155 01
4
добавление в комментарий @VitalyB. Слияние также не появляется, если обе ветви внесли одинаковые изменения в файл. Например, обе ветки увеличили версию на 1, а вы хотели бы увеличить на 2 при попытке слияния ... Очень практическая проблема, пока не
решенная
1

Эти две команды, похоже, имеют тот же эффект, что и использование настраиваемого драйвера слияния:

git merge --no-commit your_target_branch
git checkout --conflict merge .   (do not forget the . and run it in the top dir of the repository)

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

Луизиуоль
источник
Мне нравится идея «одноразового» решения (я только что столкнулся с таким случаем), однако у меня это не сработало. Git выполнил FF, что привело к неудачному слиянию (по сути, это было слияние и наше).
Nero gris
@Nerogris Действительно, это не будет работать для слияния с перемоткой вперед. Вы всегда можете добавить параметр --no-ff, но вторая команда не вызовет конфликта, так как нет изменений от общего предка в одной из двух ветвей слияния.
louisiuol
В моей глобальной конфигурации для ff установлено значение false. Когда я сказал, что это слияние FF, я имел в виду, что если бы я не сказал Git, чтобы он этого не делал, он бы сделал это.
Nero gris
0

Примечание: эта статья « Написание драйвера слияния git для файлов PO » иллюстрирует вид манипуляций, которые вы можете выполнять при слиянии файла вручную: вы можете предварительно обработать его, чтобы при ручном слиянии были готовы определенные данные.

git merge-fileможет использоваться, например, для РАСШИФРОВКИ (и повторного шифрования) файлов перед объединением (!)

В вашем случае выход из вашего драйвера слияния со статусом, отличным от 0, гарантирует, что слияние будет ручным.

VonC
источник
2
Не могли бы вы подробнее рассказать о ссылке «драйвер слияния для файлов PO», потому что это, похоже, приводит к отказу в доступе для меня? Я надеюсь, что он даст ответ на вопрос stackoverflow.com/questions/16214067/…
Микко Ранталайнен
@MikkoRantalainen заблокирован на работе, поэтому я попробую сегодня вечером дома.
VonC
1
"Драйвер слияния PO-файлов" у меня тоже не работает :(
1
@sampablokuper Согласен: статья заблокирована для "неавторизованного" читателя. Я не знаю почему.
VonC
1
@sampablokuper У меня сейчас нет доступа к этому блогу. Я буду искать его содержание.
VonC