Каковы три файла в трехстороннем слиянии для интерактивного перезагрузки с использованием git и meld?

Скажем, я делаю интерактивную перезагрузку с помощью git rebase -i. Если возникает какой-то конфликт, я могу столкнуться с конфликтом слияния и попросить сделать трехстороннее слияние. Используя meld, мне представлены три окна: LOCAL (слева), ??? (средний) и REMOTE (справа). Здесь ??? я имею в виду просто, что meld не предоставляет специального имени для добавления в файл.

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

Что представляют собой эти файлы в трехмерном объединении, представляемые во время интерактивной переадресации? А при редактировании этих файлов, какова моя цель?

Обновление: Основываясь на комментариях и экспериментах, которые я вижу:

  • Влево (LOCAL): Ваша локальная версия файла в этот момент в последовательности повторов фиксации.
  • Вправо (REMOTE): Состояние файла сразу после текущего фиксации было первоначально применено.
  • Средний: родительский элемент права в исходной последовательности фиксации.

Моя задача, таким образом, определить дельта от среднего до правого, а затем применить эту дельта к левой. Средство должно отражать состояние файла после того, как в новой последовательности фиксации применяется текущая фиксация фиксации.

Обратите внимание, что эта конфигурация, по-видимому, специфична для meld, по крайней мере в некоторой степени. Git 3-стороннее поведение слияния может отличаться для других редакторов.

4
03 мая '16 в 3:24
источник поделиться
2 ответов

Средняя версия - это база слияния, как и с git merge.

(Имя "другое" может быть более подходящим, чем "remote", поскольку нет требования, чтобы другая сторона слияния была удаленной, и поскольку Mercurial последовательно использует для нее имя "другое", а не

Но подождите, как там база слияния?

Всегда существует база слияния.

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

(Кстати, вы можете отключить этот резерв. См. --3way, --no-3way и am.threeWay в документация git -am, хотя связанная страница уже устарела, поскольку эти элементы управления недавно изменились.)

$ git rebase -i
pick aaaaaaa first commit
pick bbbbbbb second commit
pick ccccccc third commit

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

              A - B - C   <-- branch
            /
... - o - *
            \
              G - H       <-- origin/branch

Мы собираемся забирать червя A, B и C (A= aaaaaaa и т.д.), чтобы мы получили этот результат: в конце:

              A - B - C   [abandoned]
            /
... - o - *           A' - B' - C'   <-- branch
            \       /
              G - H       <-- origin/branch

Посмотрите внимательно на первый вишневый выбор, A.

Это сравнивает (diffs) A с его родителем, который является commit *, и пытается применить полученный diff к commit H.

Commit H, однако, немного отклонился от commit *. Фактически, мы можем найти базу слияния между A и H, и это... commit *. Это на самом деле довольно приличная база слияния, хотя лучше всего, если Git может просто применить патч как есть, без необходимости возвращаться к трехстороннему слиянию.

Итак, commit * является базой слияния при наборе вишни A на H. Когда слияние выполнено, мы получаем новый commit A'. (Его новый идентификатор SHA-1 может быть, например, aaaaaa1. Вероятно, нет, просто позвоните ему A'.)

Теперь мы выберем cherry-pick B. Это отличает B от его родителя, который равен A, и пытается применить diff к A'.

Commit A', однако, немного отклонился от commit B. Фактически, мы можем найти базу слияния между B и A', а это... commit * снова. К сожалению, это жалкая база слияния. К счастью, Git возвращается к нему только тогда, когда патч не может быть применен как есть, и обычно он может. Но если он не может, Git будет diff * vs B и * vs A' и попытаться объединить эти два diff. Заметим, что * vs B содержит все изменения, внесенные нами в A, но * vs A' также включает все те же самые изменения A, поэтому, если нам повезет, Git уведомления уже включенные изменения и не дублируют их. изменить Git читы. (Этот код недавно изменился в версии 2.6, хотя общая стратегия остается неизменной.)

Рассмотрим фактический вывод git diff при использовании для отображения только изменения с commit A для фиксации B. Это включает строку index:

diff --git a/foo b/foo
index f0b98f8..0ea3286 100644

Значение слева представляет собой (сокращенный) хеш для версии файла foo в commit A. Значение справа - хэш для версии файла в commit B.

Git просто подделывает базу слияния с левой стороны хэша. Другими словами, версия файла в commit A становится поддельной базой слияния. (Git передает --build-fake-ancestor в git apply). Это требует, чтобы конкретные объекты блочных объектов были в репозитории, но они есть, поскольку они находятся в commit A. Для почтовых исправлений Git использует этот же код, но blob может присутствовать или не присутствовать.)

Обратите внимание, что Git на самом деле делает это при фиксации cherry-picking A, но на этот раз базовым файлом слияния является версия от commit *, которая действительно является базой слияния.

Наконец, мы заштриховываем C. Это отличает B vs C, так же, как мы в последний раз различали A vs B. Если мы применим патч как есть, хорошо; Если нет, мы возвращаемся к использованию commit * в качестве базы слияния снова. Это еще раз довольно убогая база слияния. так же, как и раньше, притворяясь, что версия в B является общей базой.

Это также объясняет, кстати, почему вы часто сталкиваетесь с одинаковыми конфликтами слияния снова и снова для этих переустановок: каждый раз мы используем одну и ту же базу слияния. (Включение git rerere может помочь.)

5
03 мая '16 в 3:56
источник

Слияние и перестановка идентичны в этом отношении. Единственное различие между слиянием и переустановкой состоит в том, что история выглядит более приятной (более линейной) с rebase. Но в отношении конфликтов, которые возникнут и которые вы должны решить, они одинаковы.

-1
03 мая '16 в 3:31
источник

Посмотрите другие вопросы по меткам или Задайте вопрос