Ответ 1
TL; DR
Флаг --preserve-merges
просто сообщает git-rebase
попытаться воссоздать комманды слияния вместо их игнорирования. Он не дает git rebase
способности запоминать, как конфликты слияния были разрешены, т.е. Он не записывает разрешения конфликтов для будущего использования. То, что вы хотите использовать для этого, rerere
.
В вашем примере игрушек конфликт, возникающий во время rebase, точно такой же, как тот, который вы разрешили во время предыдущего слияния. Если вы активировали rerere
до слияния, вам не пришлось бы снова разрешать этот конфликт во время rebase.
Если вы ожидаете, что вы объединитесь, то пересоедините ветвь, вы должны активировать rerere
, чтобы в будущем вам нужно было разрешить данный конфликт слияния один раз, а не несколько раз.
Подробное объяснение
Позвольте сломать ваш пример с игрушкой.
git init
echo Hello > Hello.txt
git add Hello.txt
git commit -m "Create Hello.txt (commit A)"
git tag start
echo World! >> Hello.txt
git commit -am "Change to Hello World (commit B)"
git checkout start
git checkout -b branch
echo Dave >> Hello.txt
git commit -am "Change to Hello Dave (commit C)"
До сих пор так хорошо. Прямо перед вашей первой командой git merge
ваше репо выглядит следующим образом:
В фиксации A, Hello.text
содержит
Hello
В commit B, Hello.text
содержит
Hello
World!
И в commit C, Hello.text
содержит
Hello
Dave
Теперь, когда вы пытаетесь объединить master
в branch
, запустив
git merge master
Git сообщает о конфликте слиянием, поскольку он не может самостоятельно определить, должно ли содержимое Hello.txt
после слияния
Hello
World!
Dave
или
Hello
Dave
World!
или что-то еще...
Вы разрешаете этот конфликт, перезаписывая содержимое Hello.txt
с помощью Hello World, Dave!
, размещая свои изменения и завершая фиксацию слияния.
echo "Hello World, Dave!" > Hello.txt
git add Hello.txt
git commit -m "Merge branch master into branch (commit D)"
Теперь ваше репо выглядит следующим образом:
Затем вы запустите
git checkout start
git checkout -b goodbye-branch
echo Goodbye > Goodbye.txt
git add Goodbye.txt
git commit -m "Add Goodbye.txt (commit E)"
На этом этапе ваше репо выглядит следующим образом:
Теперь вы запустите
git checkout branch
git rebase -p goodbye-branch
но испытывает конфликт. Прежде чем объяснять, почему возникает этот конфликт, давайте посмотрим, как будет выглядеть ваше репо, если эта операция git-rebase
была успешной (т.е. Конфликт свободен):
Теперь посмотрим, почему вы столкнулись с тем же конфликтом в Hello.txt
, что и во время вашего первого слияния; Goodbye.txt
здесь не проблема. Бабаза может быть фактически разложена в последовательности более элементарных операций (checkout
и cherry-pick
s); подробнее об этом на http://think-like-a-git.net/sections/rebase-from-the-ground-up.html.
Короче говоря... В середине вашей операции git rebase
ваше репо будет выглядеть следующим образом:
Ситуация очень похожа на ситуацию перед вашим первым слиянием:
в commit B ', Hello.text
содержит
Hello
World!
И в commit C ', Hello.text
содержит
Hello
Dave
Затем Git пытается создать слияние B 'и C', но конфликт слияния возникает по той же причине, что и первый конфликт слияния, который вы испытали: Git не имеет способа определить, будет ли строка Dave
должен идти до или после строки World!
. Таким образом, операция rebase останавливается, и Git просит вас разрешить конфликт слияния, прежде чем он сможет завершить rebase.
Что вы можете с этим сделать: используйте rerere
Git rerere
является вашим другом, здесь.
Название означает "повторное использование записанного разрешения" и, как следует из названия, оно позволяет вам спросить Git запомнить, как вы разрешили конфликт с hunk, чтобы в следующий раз, когда он увидел тот же конфликт, Git может автоматически разрешить его для вас.
[...], если вы хотите взять ветку, которую вы объединили, и устранили кучу конфликтов, а затем решили переустановить ее - вам, вероятно, не придется повторять все те же конфликты.
Если rerere
был включен,
git config --global rerere.enabled true
до слияния, тогда Git записал бы, как вы разрешили конфликт слияния при создании commit D, и применили бы то же разрешение, когда столкнулись с тем же конфликтом во время последующей перезагрузки. Конфликт все равно прервал бы операцию переустановки, но это было бы автоматически разрешено. Все, что вам нужно было бы сделать, это git rebase --continue
.
Однако, похоже, что rerere
не было активировано до слияния, что означает, что Git не должен записывать, как вы разрешили конфликт в первый раз. На этом этапе вы можете активировать rerere
сейчас и снова разрешить все те же конфликты вручную или использовать rerere-train.sh
script ( см. также сообщение в блоге), чтобы использовать существующую историю для предварительного семени кэша rerere
.