git, объединяйтесь с помощью инструмента, а не разрешайте с помощью инструмента

Я пришел из mercurial, и есть одна вещь, которую я не знаю, как делать с git.

В mercurial во время слияния каждая версия конфликтующего файла (базовая, другая и локальная) представлена ​​рядом в моем любимом инструменте слияния (kdiff3 или meld). Сливаю их, сохраняю результат и все довольны.

С git я git merge и в случае конфликтов я git mergetool ... и получаю файлы, полные ужасов, как этот беспорядок:

first line
<<<<<<< HEAD
local line
=======
other line
>>>>>>> other-branch
last line

Как настроить git для открытия моего любимого инструмента слияния до возникновения конфликта? Я хотел бы слить вручную, а не разрешать вручную :)


person yota    schedule 25.11.2019    source источник
comment
То, что вы здесь называете хоррором, похоже на самый четкий и красивый конфликт, который я когда-либо видел :'-) Желаю каждому моему другу побольше такой захламленной каши. Если серьезно, вы, вероятно, просто приспосабливаетесь к другой (несколько похожей, но не совсем) парадигме. Какая у вас практическая проблема? Потому что это больше похоже на временный дискомфорт, чем на реальную проблему.   -  person RomainValeri    schedule 25.11.2019
comment
это был бы хороший способ представить, если бы я объединился с nano или любым другим текстовым слиянием ... но я использую kdiff3, и для КАЖДОГО конфликта мне нужно редактировать вручную, а не просто быстро щелкнуть: здесь выберите локальный, здесь база, тут другое... Мы выше дискомфорта :D   -  person yota    schedule 25.11.2019
comment
Существует множество инструментов слияния для разрешения конфликтов простыми щелчками, как вы описали (даже если некоторые гринчи, такие как я, настаивают на текстовом разрешении), я подозреваю, что это простая ошибка конфигурации. Какая у вас ОС?   -  person RomainValeri    schedule 25.11.2019


Ответы (1)


(Предварительное примечание: я не использую ни один из этих инструментов. Вместо этого я устанавливаю merge.conflictStyle в diff3, который использует немного другой формат разметки в файле рабочего дерева. В большинстве случаев я могу легко решить эту проблему непосредственно в vim. Если это слишком беспорядочно, иногда я буду использовать git show для прямого извлечения трех входных данных, например, git show :1:path. Но все разные, поэтому см. настройте KDiff3 как инструмент слияния и инструмент сравнения.)

Как настроить git так, чтобы мой любимый инструмент слияния открывался до возникновения конфликта?

Вы не можете. Что ж, вы могли бы, если бы написали свою собственную стратегию слияния — эквивалент git merge-recursive — но никто не делал ничего подобного уже много лет, потому что это слишком сложно. К счастью, вам не нужно:

Я хотел бы слить вручную, а не разрешать вручную :)

Если возникает конфликт, Git записывает собственную попытку слияния с файлом рабочего дерева.1 Это то, что вы видите здесь в своем редакторе. Но Git оставил три входных файла в том, что Git называет по-разному: index, staging area и (редко в наши дни) cache. Это три имени для одного и того же: staging area относится к тому, как вы его используете, а cache относится к различным внутренним аспектам и index это какой-то бессмысленный термин. В этом случае лучше всего использовать слово «индекс», и я буду использовать его здесь.

Когда вы запускаете git mergetool, Git должен запустить выбранный вами инструмент слияния для всех трех входных файлов, а также для четвертого (Git-attempt-at-merge с маркерами конфликта) файла рабочего дерева. Затем этот инструмент может показать вам некоторые или все эти различные входные данные. Затем вы можете использовать инструмент, независимо от того, как работает сам инструмент, чтобы выполнить разрешение вручную, полностью игнорируя попытку Git выполнить слияние, если хотите.

Обратите внимание, что три входных файла — база слияния, левый или локальный наш --ours и правый или удаленный или --theirs — которые git mergetool предоставляет вашему инструменту слияния, являются просто временными файлами. Они не будут использоваться в качестве результата слияния. Файл, который будет использоваться в качестве результата слияния, когда ваш инструмент слияния сообщит Git, что слияние завершено, является основным файлом рабочего дерева: тем, в котором есть беспорядок. Таким образом, ваш инструмент должен перезаписать этот файл результатом слияния.

В отличие от Mercurial, ядро ​​Git не имеет встроенных инструментов слияния (ну, кроме своего собственного по умолчанию, который он все равно всегда запускает, как часть стратегии слияния, которую вы выбираете с помощью -s). Следовательно, вы или кто-то, кто настраивает для вас дистрибутив Git, должны указать Git, как запускать какой-либо конкретный внешний инструмент слияния. Каждая установка Git, как правило, будет иметь некоторый набор предварительно настроенных внешних инструментов слияния, которые могут включать или не включать нужный вам инструмент. Если вам нужно настроить собственный внешний инструмент слияния, см. раздел Git в Windows: как настроить инструмент слияния? (несмотря на заголовок, некоторые из его ответов хороши для систем, отличных от Windows. См., в частности, ответ CB Bailey.)

Четыре имени, с которыми должен работать ваш инструмент слияния, предоставляются как переменные среды: $BASE — имя базового файла слияния (из промежуточного слота № 1 в индексе), $LOCAL — имя файла --ours (промежуточный слот № 2 в индексе), $REMOTE — имена. файл --theirs (промежуточный слот №3), а $MERGED – это имя файла, который git mergetool ожидает, что ваш инструмент слияния обновит его до того, как инструмент слияния сообщит об успешном или неудачном выполнении скрипта git mergetool2.


1Помните, что Git хранит пригодные для использования копии ваших файлов в вашем рабочем дереве, но на самом деле создает коммиты из файлов специального формата Git, которые хранятся (косвенно) в индексе. Во время конфликтного слияния Git просто оставляет все три входных файла в индексе, используя ненулевые номера слотов индекса. Файл, который, по мнению Git, он разрешил сам по себе, помещается в обычную запись индекса с нулевым слотом, стирая ненулевые слоты, поэтому три входных файла здесь не так легко доступны. (На мой взгляд, это своего рода дефект, но Git не спрашивает моего мнения. Технически Git даже не записывает записи файлов в ненулевые слоты индекса, если он может тривиально объединить их при обработке файлов. Это вероятно для скорости и/или лени.)

2Ваш инструмент должен сигнализировать об успешном или неудачном завершении с помощью кода выхода на уровне ОС. Если это так, и вы настроили этот инструмент с trustExitCode установленным на true, git mergetool будет знать, следует ли автоматически git add файл $MERGED. Если вы настроите trustExitCode на false, git mergetool будет использовать некоторую эвристику, чтобы угадать, верить ли, что инструмент успешно объединил файлы.

person torek    schedule 25.11.2019
comment
Спасибо за этот очень подробный ответ! Я утверждаю, что это невозможно по замыслу... Я проверю вариант diff3! (и оплакивать потерю меркуриала на битбакете † аминь :) - person yota; 25.11.2019
comment
За исключением введенных команд, вы сможете заставить свою систему обеспечивать тот же пользовательский интерфейс, даже несмотря на то, что фактический код слияния Git довольно сильно отличается. (Я также использовал vim для решения проблем в Mercurial, просто это мой предпочтительный метод.) - person torek; 25.11.2019