Технически, вы не можете ничего изменить ни в одном существующем коммите.
Это означает, что для того, чтобы "изменить" b
на B
, вам действительно нужно сделать новый и улучшенныйB
. Старый b
будет продолжать существовать (как долго, это совсем другой вопрос). Обычный git rebase
, интерактивный или нет, работает путем копирования коммитов в новые и улучшенные. Регулярная перебазировка также удаляет слияний и выравниваний, как вы заметили.
Начиная с Git 2.18, git rebase
имеет режим, называемый --rebase-merges
. Это сохраняет слияния - или, точнее, повторно создает их как новые коммиты слияния, буквально снова запуская git merge
. До версии 2.18, git rebase
имеет -p
, который использует механизм интерактивной перебазировки, а также сохраняет слияния (повторяя их). Он несколько неисправен по сравнению с более привлекательной новой версией, но - я думаю (не проверял!) - должен работать в этом случае.
Следовательно, используйте git rebase -i --rebase-merges
так же, как и git rebase -i
. Если вам не хватает --rebase-merges
, обновите версию Git или используйте git rebase -i -p
и будьте очень осторожны, чтобы не нарушать порядок различных операций или не создавайте новую цепочку вручную.
Чтобы построить ее с помощьюрукой, запустите git checkout
на коммите B
. Вы можете назначить новое имя ветви здесь, если хотите, или просто выполнить всю операцию с отсоединенным HEAD
способом git rebase
:
git checkout -b temp-rebuild <hash-of-b>
для использования нового временного имени ветви, дляэкземпляр. Затем используйте git commit --amend
(возможно, сначала с дополнительным материалом), чтобы создать новый B
:
B <-- temp-rebuild
/
a---b---c---d---i---j---k---o <-- master
\ / /
e---f---g---h---l---m---n <-- develop
Теперь запустите git cherry-pick
для хеша коммита c
, чтобы скопировать его в новый коммит C
и повторите для d
:
B---C---D <-- temp-rebuild
/
a---b---c---d---i---j---k---o <-- master
\ / /
e---f---g---h---l---m---n <-- develop
Теперь запустите git merge
для хэша коммита h
, i
второго родителя, чтобы произвести новое слияниеI
, при необходимости разрешая любые конфликты слияния:
B---C---D------I <-- temp-rebuild
/ /
a---b---c---d--/i---j---k---o <-- master
\ |/ /
e---f---g---h---l---m---n <-- develop
Используйте больше команд cherry-pick и merge для завершения процесса:
B---C---D------I---J---K--O <-- temp-rebuild
/ / /
a---b---c---d--/i---j---k-|-o <-- master
\ |/ |/
e---f---g---h---l---m---n <-- develop
Теперь, когда созданы новые коммиты,заставить имя master
указывать на окончательный коммит и прекратить рисовать старую цепочку b-c-d-i-j-k-o
, и вы получите то, что хотели. Вот что делают git rebase --rebase-merges
и git rebase -p
: -p
просто использует хрупкий алгоритм, который, в то время как --rebase-merges
использует новый формат интерактивного листа инструкций, который позволяет вам указывать новый график таким образом, чтобы он не ломался привы двигаетесь коммиты.