Git повторно объединить файл, используя другой вариант стратегии объединения? - PullRequest
0 голосов
/ 01 июня 2018

Я объединяю две ветви с общим предком:

> [branch1]
git merge branch2 --no-commit
# ... did merging for several files with conflicts
git merge branch2 -srecersive -Xignore-space-at-eol -- myfile.txt  # not possible

И я разрешил несколько конфликтов слияния в файлах, которые я хочу сохранить.Теперь есть файл с конфликтами, которые из-за символов новой строки отличаются.Как я могу сделать git, чтобы игнорировать конфликты символов новой строки и создать другой файл с конфликтами, с опцией ignore-space-at-eol из recursive стратегии, т.е.что-то в этом роде git merge branch2 -srecursive -Xignore-space-at-eol -- myfilewithconflicts.txt.Смотрите картинку.Я могу отменить слияние файла (git checkout -m myfilewithconflicts.txt), но как применить к этому файлу другую стратегию?

enter image description here

1 Ответ

0 голосов
/ 01 июня 2018

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

Git действительно должен иметь инструмент «приостановить слияние», чтобы позволить вам сделатьэто чище.Возможно, можно написать один, но у меня нет времени, чтобы сделать это.

Почему это так (долго)

Давайте начнем с некоторого фона.Проблема на данный момент сводится к выполнению трехсторонних слияний на отдельных файлах - но как мы сюда попали?

Типичное слияние Git - или, точнее, то, что я привык называть истинное слияние , в отличие от операции "ускоренной пересылки", которая выполняется не по принципу слияния, которая в основном выполняется просто, как через git checkout или git reset --hard, и использует три входа.Вы указываете один из этих входных данных, --theirs commit.Два других являются неявными: это текущий или --ours коммит и база слияния , рассчитанная вашей стратегией слияния .Стратегия по умолчанию для этого вида слияния - та, которую вы выбрали в обеих примерах команд: -s recursive.

цель этого вида слияния - объединить работу.Фиксация базы слияния служит общей отправной точкой, с которой вы (в своей ветви --ours) выполнили некоторую работу, а они (в своей ветви --theirs) выполнили некоторую работу, которую Git теперь должен объединить.Поскольку вы оба начали с одного и того же коммита, это облегчает объединение: Git может запустить git diff из базы слияния в ваш коммит, чтобы увидеть, что вы сделали, и второй git diff от слиянияОсновываясь на их коммите, чтобы увидеть, что они сделали.

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

Игнорируя сложные случаи, такие как новые файлы, переименованные файлы и удаленные файлы, теперь у нас есть стратегия слияния, для каждого имени пути P:

  • посмотрите на содержимое P в базе слияния;
  • посмотрите на содержание P в коммите --ours
  • посмотрите на содержимое P в коммите --theirs.

В качестве кратчайшего пути, если содержимое одинаково в двух илитри из трех версий, объединить нечего, и Git может просто выбрать версию --ours, которая уже есть в индексе, или поместить версию --theirs в индекс в зависимости от ситуации.

Если нет, хотя - если все три версии отличаются - тогда этот конкретный файл требует фактического слияния.Git копирует все три версии в индекс в слотах 1, 2 и 3, которые зарезервированы для процесса слияния, и вызывает код слияния , один файл за один раз .Этот код объединяет один файл , используя три версии .Три версии - это те, которые теперь хранятся в индексе (мы можем извлечь все три в рабочее дерево позже, если захотим, но это то, где они есть).

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

Вы не можете начать новое слияние, если у вас есть неполное слияние

Примечаниечто в приведенной выше последовательности Git использует индексную / промежуточную область для хранения трех версий каждого конфликтующего файла и рабочее дерево для хранения объединенной версии при остановке.Для этого Git должен начинаться с индекса clean и рабочего дерева.Если бы индекс и рабочее дерево не были чистыми для начала, этот процесс мог бы уничтожить несохраненную работу.

Поэтому Git говорит «нет», если вы пытаетесь запустить git merge с неразрешенным конфликтом слияния илинезафиксированный индекс или грязное рабочее дерево.Если вы прервите существующее, продолжающееся слияние, это уничтожит все, что вы сделали до сих пор, и переустановит ваш индекс и рабочее дерево так, чтобы они были чистыми, но это уничтожит все, что вы сделали до сих пор.

Ваш единственный вариант - закончить слияние - пометить все решенные и зафиксировать.Но это создает новый коммит в текущей ветке.Если затем вы начнете второе слияние, подразумеваемая база слияния - это только что сделанный вами коммит, а не исходная база слияния, которая была у вас во время предыдущего коммита.Это означает, что вы должны сохранить коммит слияния, но затем отменить его с git reset или его эквивалентом.Это сложная и подверженная ошибкам часть.

Если бы мы только могли повторить низкоуровневое слияние с различными параметрами

В низкоуровневом коде используется большая часть-X опций, например -X ours или -X theirs, или, в вашем случае, -X ignore-space-at-eol.Если бы у нас был прямой доступ к этому низкоуровневому коду, мы могли бы просто запустить его сами.Это позволило бы нам добавить -X ignore-space-at-eol для одного конкретного файла, в котором имел конфликты.

К сожалению, в то время как есть команда git merge-file, это не код, который используется git merge-recursive (код merge-recursive в ll-merge.c, который реализует объединение низкого уровня, а не merge-file.c, который реализует git merge-file).Команда merge-file не принимает опции -X.Это делает , берет --ours, --theirs и даже --union.Он вызывает код, который может принять -X ignore-space-at-eol, но у него нет параметра командной строки, чтобы установить это.Если бы это заняло -X ignore-space-at-eol, вы бы смогли достичь того, что хотели напрямую.

...