Git трехстороннее объединение на файлах, уже помеченных как объединенные - PullRequest
0 голосов
/ 17 апреля 2019

Чтобы сохранить историю разрешения конфликтов при слиянии от главной ветви к ветви разработки, я делаю фиксацию состояния как есть, а затем еще одну фиксацию разрешения конфликта.

В первом коммите я ничего не делаю для разрешения конфликта, поэтому все "<<<<<<<< ========= >>>>>>>>"хранится в исходном коде.Во втором коммите я явно разрешаю конфликт.

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

1 Ответ

1 голос
/ 17 апреля 2019

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

Три входных файла:

  • версия слияния версия;
  • левая сторона или --ours или HEAD или "местная" версия; и
  • правосторонняя или --theirs или "удаленная" версия.

Когда вы редактировали файл рабочего дерева и видели:

auto-merged result text
<<<<<<< HEAD
some text
=======
different text
>>>>>>> their-branch
more auto-merged text

текст, который вы видели, был лучшим усилием Git по объединению этих трех входов. Фактические входные данные составляли в индексе в то время как «этап 1», «этап 2» и «этап 3» соответственно. Например, если вы запустили git mergetool для завершения слияния, команда git mergetool использовала git checkout-index для извлечения этих трех файлов (которые назывались BASE, LOCAL и REMOTE).

Когда вы совершили слияние, Git удалил три входа. Они больше не доступны. Вы можете обычно найти их снова. Вот откуда они пришли:

  • Файл базы слияния был извлечен из базового коммита слияния.

    Чтобы найти хеш-идентификатор базовой фиксации слияния, используйте git merge-base --all. Вам также понадобятся два других хеш-идентификатора коммита. Если итоговый идентификатор базы слияния, скажем, bbbbbbb, вы можете запустить:

    git show bbbbbbb: путь / к / файлу> file.base

    для восстановления базовой копии файла слияния в текущем рабочем дереве.

  • Левый файл вероятно вышел из коммита, который вы использовали в то время. (Исключение из этого правила возникает, когда вы используете измененный файл рабочего дерева в качестве файла левой стороны. В этом случае версия для левой стороны не может быть восстановлена ​​через Git вообще.) Так что вам понадобится этот хэш-идентификатор. Допустим, это 1111111; то:

    git show 1111111:path/to/file > file.local
    

    воссоздаст этот ввод в текущем рабочем дереве.

  • Наконец, файл с правой стороны вышел из коммита, который вы объединяли. Вам понадобится этот последний хэш-идентификатор коммита. Допустим, это 2222222; то:

    git show 2222222:path/to/file > file.remote
    

    воссоздаст этот вход в текущем рабочем дереве.

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

Если у вас есть все три входа, вы можете использовать команду git merge-file , чтобы объединить их, так же, как git merge. Это оставит объединенный результат с маркерами конфликта в одном из этих трех файлов. Подробности смотрите в связанной документации.

Наконец, обратите внимание, что вы можете повторно запустить слияние, проверив фиксацию then- HEAD как отсоединенный HEAD . Вы можете найти и тогдашний HEAD, и другие хэш-идентификаторы коммитов, изучив коммит слияния: у него есть два родителя, и эти два родителя являются коммитами слева и справа соответственно. Так что если коммит слияния имеет хеш-идентификатор $M, то:

git checkout $M^1     # detach HEAD at left side commit
git merge $M^2        # re-execute the merge with right hand side commit

будет повторять работу, которую git merge выполнил в первый раз, вычисляя ту же базу слияния и выполняя ту же работу слияния и создавая те же конфликты слияния. См. документацию gitrevisions для более подробной информации о нотациях <revision>^1 и <revision>^2. Когда конфликты повторяются, записи более высокого уровня снова будут в вашем индексе.

...