Когда 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 тема переходит к новым коммитам, удаляет фальшивую ветвь.