Когда git перезагрузка двух ветвей с некоторой общей историей, есть ли простой способ, чтобы общая история оставалась общей?
Предположим, что мы имеем следующий график пересмотра:
A-X-Z--B
\
\-C
с A, предшествующим как B, так и C. Далее предположим, что я перебазирую A из восходящего потока, создавая новый commit A *, а затем переставляю B и C на A *. Полученный результирующий граф выглядит следующим образом:
A*-X'-Z'-B
\
\-X"-Z"-C
Обратите внимание, что общая история больше не используется. Есть ли простой способ исправить это, кроме, скажем, переустановки B, а затем явным образом перегрузить C на Z '. Другими словами, есть ли лучший способ автоматически переустанавливать несколько ветвей одновременно, чтобы сохранить общую историю? Кажется немного неудобным либо искусственно размещать тег в точке разделения, либо вручную проверять график, чтобы узнать sha1 коммита, на котором нужно переустановить C, чтобы сохранить общую историю, не говоря уже об открытии возможности ошибок, тем более, что я должен делать это каждый раз, когда я переустанавливаю, пока не проверю изменения в ветке вверх по течению.
Ответы
Ответ 1
git rebase --committer-date-is-author-date --preserve-merges --onto A* A C
git rebase --committer-date-is-author-date --preserve-merges --onto A* A B
Это должно содержать общие коммиты, имеющие один и тот же sha1, и любые слияния сохраняются. Сохранение слияний не требуется в этом случае, но станет проблемой с менее тривиальной историей.
Чтобы сделать это для всех ветвей, содержащих A в их истории, выполните:
git branch --contains A | xargs -n 1 git rebase --committer-date-is-author-date --preserve-merges --onto A* A
Надеюсь, что это поможет.
UPDATE:
Это может быть более чистый синтаксис:
for branch in $(git branch --contains A); do git rebase --committer-date-is-author-date --preserve-merges --onto A* A $branch; done
Ответ 2
Задача в общем случае
Мне была задана аналогичная проблема: перезагрузка целой предыстории - несколько ветвей с некоторыми связями между ними, возникающими в результате слияния:
A--B-B2-topicB
\ /
\-C-C2-topicC
Если я выполняю несколько git rebase
последовательно (для topicB и topicC), я сомневаюсь, что слияния между ветвями могут быть сохранены правильно. Таким образом, я бы должен был перегрузить все ветки сразу, надеясь, что это правильно восстановит их.
"Решение", работающее в конкретном подкадре
В моем случае мне посчастливилось, что topicC фактически слит в topicB, поэтому я мог бы переустановить всю предысторию, я мог просто запустить
git rebase -p A* topicB'
(A * - это новая база, как и в вашем вопросе), а затем reset все оставшиеся отрезки ref (и теги) к новым соответствующим коммитам (в новой предыстории), например
git branch -f topicC C3'
Это сработало. (Перемещение ссылок ref и тегов возможно возможно с помощью script.)
"Решение" для общего случая, вдохновленного этим конкретным
Если topicC не был объединен в topicB, я мог бы создать фальшивую верхнюю фиксацию для объединения всех ветвей, которые я хочу переустановить, например:
git checkout -b fake topicB
git merge -s ours topicC
а затем переустановите его таким образом:
git rebase A* fake
и reset тема переходит к новым коммитам, удаляет фальшивую ветвь.