Я хочу выполнить трехсторонний разграничение между двумя ветвями git с общей базой слияния и просмотреть его с помощью kdiff3.
Я нашел много рекомендаций по SO (и несколько очень похожих вопросов (1, 2, 3)), но я не нашел прямого ответа. Примечательно, что комментарий этого ответа подразумевает, что я хочу, но это не сработало для меня. Надеюсь, этот пользователь может прослушивать здесь:)
Для фона, когда я выполняю слияния, я использую стиль конфликта "diff3":
git config --global merge.conflictstyle diff3
И у меня git mergetool
настроено на использование kdiff3.
При разрешении конфликтов слияния это показывает мне четыре файла:
- Текущий файл ветки ($ LOCAL)
- Другой файл ветки ($ REMOTE)
- Файл, являющийся общим предком двух ветвей ($ BASE)
- Объединенный выходной файл ($ MERGED)
Однако git difftool
только подтянет две подсказки ветки. Я тоже хочу увидеть базовый файл. Чтобы быть ясным, я хочу иметь возможность выполнить этот diff перед слиянием, в том числе в файлах без конфликтов слияния. (git mergetool
показывает только трехсторонние различия, если есть конфликты).
Частичное решение № 1:
В отдельном файле я могу экспортировать три версии и вручную вызвать diff:
git show local_branch:filename > localfile
git show remote_branch:filename > remotefile
git show `git merge-base local_branch remote_branch`:filename > basefile
{kdiff3_path}/kdiff3.exe --L1 "Base" --L2 "Local" --L3 "Remote" -o "outputfile" basefile localfile remotefile &
Есть две проблемы с этим:
- Я хочу, чтобы он работал для всего проекта, а не только для определенного файла.
- Это некрасиво! Я могу script его, но я надеюсь, что там будет гораздо более чистый способ использования стандартных процессов git.
Частичное решение №2:
Благодаря этому ответу и comment для вдохновения.
Создайте пользовательский драйвер слияния, который всегда возвращает "false", что создает конфликтное состояние слияния без фактического автоматического слияния. Затем выполните diff с помощью git mergetool
. Затем прервите слияние, когда закончите.
-
Добавить в
.git/config
:[merge "assert_conflict_states"] name = assert_conflict_states driver = false
-
Создайте (или добавьте)
.git/info/attributes
, чтобы заставить все слияния использовать новый драйвер:* merge=assert_conflict_states
-
Выполните слияние, которое теперь не выполняет никаких операций.
-
Сделайте разницу. В моем случае:
git mergetool
, который вызывает трехстороннее слияние kdiff3. -
Когда закончите, отмените слияние:
git merge --abort
. -
Отменить шаг № 2.
Это будет (sorta) работать, за исключением того, что kdiff3 выполняет автоарьер при вызове, поэтому я все еще не могу видеть предварительно сложенные различия. Однако я могу исправить это, изменив файл драйвера wd > wkk kdiff3 (.../git-core/mergetools/kdiff3
, удалив переключатель --auto
.
Тем не менее, это имеет следующие проблемы остановки:
- Это работает только тогда, когда оба файла изменились! В случае, когда только один файл изменился, обновленный файл заменяет старый файл, и слияние никогда не вызывается.
- Мне нужно изменить драйвер git kdiff3, который вообще не переносится.
- Мне нужно изменить
attributes
до и после выполнения diff. - И, конечно же, я надеялся сделать это без слияния:)
Информация для награды:
В соответствии с полученными ответами это невозможно при использовании стандартного Git. Итак, теперь я ищу более готовое решение: как я могу настроить git, чтобы это произошло?
Здесь один вывод: по-видимому, если только один из трех файлов был изменен, этот новый файл используется в результате слияния без фактического вызова драйвера слияния. Это означает, что мой пользовательский драйвер слияния, создающий конфликт, никогда не вызывается в этом случае. Если бы это было так, то мое "Partial Solution № 2" действительно функционировало бы.
Можно ли изменить это поведение путем настройки файлов или конфигураций? Или, может быть, есть способ создать собственный драйвер diff? Я не готов начать играть с исходным кодом git...
Любые умные идеи?