Git -выход конфликта слияния

Итак, я использовал git -subtree, чтобы иметь разные ветки repoB в подкаталогах repoA, например

git clone repoA
cd repoA
// some commits to repoA here
git subtree add --prefix=src/dirA repoB branchA

Я сделал несколько коммитов в repoA, используя

git subtree push --prefix=src/dirA repoB branchA

Спустя некоторое время я совершил что-то для repoB/branchA из другого repoC, где добавлен branchA с помощью git -subtree.

Теперь я пытаюсь

git subtree pull --prefix=src/dirA repoB branchA

Однако я получаю конфликт слияния без всякой видимой причины. Изменения просты и не конфликтуют вообще - как это подтверждено патчем.

Я не уверен, как исправить эту ошибку. Я уже нашел two четыре других потока, которые касаются одной и той же/подобной проблемы:

Я не уверен, что это связано с разными SHA-1, поскольку я не переустанавливал свои коммиты и не редактировал их; ссылки с 1 по 3.

Моя проблема больше похожа на ссылку 4, где git волшебно не делает простого слияния. Однако ссылка 3 говорит о стратегии слияния поддерева, а не git -subtree, в частности, поэтому я не уверен, что это применимо вообще в моей ситуации.

Ситуация выглядит одинаково:

<<<<<<< HEAD
=======
// changes from commit I try to pull from repoB/branchA
>>>>>>> {commit SHA-1 from commit I try to pull from repoB/branchA}

Итак, я заметил, что BASE вопиюще неверна в трехстороннем окне слияния (kdiff3). Однако, если это так, почему git не пытается применить все предыдущие коммиты с базы? Выдача

git log --oneline

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

git subtree add --prefix=src/dirA repoB branchA

внутри repoA.

Итак, что происходит? Похоже, что это связано с тем, что поддерево git не может найти мои коммиты по какой-то причине, но не пытается применить фиксацию от BASE к HEAD ~ 1, но только коммит, который я действительно отсутствую, HEAD.

Как я могу исправить эту ошибку, не прикручивая историю репозитория? Почему не может git вытащить эту простую фиксацию и вместо этого считает, что это конфликт слияния?

Любое понимание будет оценено по достоинству.

Ответ 1

Хорошо, поэтому я понял это. Это была двуединая проблема. Прежде всего, мое дерево выглядело так:

Status Quo

У меня была фиксация в моем дереве, которая касалась src/dirA, но еще не была нажата, когда repoB/branchA уже был включен.

Я обнаружил, что git subtree pull не найдет правильную базу, потому что ищет общего предка, поэтому он использовал версию, когда я последний раз объединил деревья, т.е. когда я сначала набрал git subtree add.

Теперь, чтобы решить проблему общего предка, нужно git subtree split --rejoin, который выполняет поверхностное слияние, поэтому git снова находит правую базу, то есть после того, как коммиты переместились с repoA на repoB/branchA.

Однако, как вы можете видеть в моем случае, git subtree split --rejoin, за которым следует git subtree pull, не решает моих проблем:

Broken History after git subtree pull.

В связи с тем, что git subtree split создает синтетическую историю всех фиксаций, которые касаются src/dirA независимо от того, были ли они нажаты, суммы SHA-1 расходятся. Я разделил синтетическую историю на свою собственную ветвь split для демонстрационных целей.

git subtree pull, конечно, будет успешным после git subtree split --rejoin. Однако следующий git subtree push завершится неудачно, потому что истории repoB и синтетического дерева после этого полностью различаются.

Поэтому мне пришлось вернуться назад, чтобы оскорбить неподдерживаемую фиксацию и вытащить изменения в мою ветку оттуда. Это осложняется тем, что git subtree split --rejoin по-прежнему необходимо, потому что git subtree pull через git merge все еще не может определить правильную базу самостоятельно.

Final solution to my problem

Итак, способ, которым я в настоящее время разрешил свою проблему, состоял в том, чтобы проверить фиксацию непосредственно перед неподтвержденным фиксатором src/dirA. Затем я сделал git subtree split --rejoin, а затем git subtree pull. Это, конечно, добавляет два слияния в мое основное дерево, что я не мог понять, как сквоивать в одно слияние, и из того, что я читаю в исходном коде, похоже, это не простое решение этой проблемы.

После успешного git subtree pull я переустановил оставшиеся коммиты из ветки master на master_fix. Теперь суммы SHA-1 соответствуют всей общей истории repoA/master_fix и repoB/branchA.

Это, конечно, имеет обычные недостатки rebase: если кто-то другой работал над master, их история будет разрушена git branch -m master_fix master.