Как я могу перебазировать все мои локальные ветки Git (и теги), когда вышестоящая версия переписала историю? - PullRequest
9 голосов
/ 12 июля 2011

Сопровождающий конкретного (встроенного) репозитория ядра Linux изменил кучу древних коммитов, чтобы очистить историю.Как следствие, все коммиты имеют разные SHA.

Когда я получаю git fetch из этой переписанной истории, мне нужно переместить мою локальную ветвь (и) в локальную точку входа ветки отслеживания, которая соответствуетуказать в местном дереве, где мои собственные ветви начинаются.Стандартное решение:

git rebase --onto SHAxx master ownbranch

(SHAxx соответствует c2 для удаленных / источника / мастера на приведенном ниже графике).

Однако, когда у меня есть несколько собственных веток, в которых один единственный предок находится в masterЯ должен применить ребаз для каждой отдельной ветви.Вместо этого я хочу перенести все ветви с любыми связанными тегами в новую точку входа в выбранной ветви отслеживания одним действием.

Графически, состояние после выборки, перед любым действием (упрощено - за пределами слева глубокоmaster history):

    c1'--c2'--c3'--c4'--c5'--c6'--c7--c8--c9 remotes/origin/master
   /
--o--c1--c2--c3--c4--c5--c6 master
           \
            o---o---o---o---o  branch1
                     \
                      o---o  branch2 (etc.)

Если быть точным: когда моя собственная работа начинается с master commit c2, я хочу перебазировать свое собственное поддерево со всеми его тегами (если оно есть) одним действием на c2 'пульта/ origin / master (с его отличным SHA по сравнению с c2 мастера).

В то время я могу полностью удалить master и сделать удаленные / origin / master новым master с моей собственной работой:

    c1--c2--c3--c4--c5--c6  (old master, not referenced anymore)
   /
--o--c1'--c2'--c3'--c4'--c5'--c6'--c7--c8--c9 master = remotes/origin/master
            \
             o---o---o---o---o  branch1
                      \
                       o---o  branch2 (etc.)

Тогда я бы проверил, дает ли процесс сборки тот же результат, что и раньше, и если все в порядке: продолжайте постепенно объединять обновления мастера (например, для каждого шага субиндекса nn в 2.6.nn) в мою собственную (зависящую от платы) ветвь.

Или есть другой / лучший подход для достижения того же результата?

Возможное решение представлено на Перебазирование ветви, включаяng все его дочерние элементы , но теги не перемещаются.

Ответы [ 2 ]

3 голосов
/ 13 июля 2011

Ниже представлена ​​последовательность шагов, в которых используется относительно новая команда git replace.Используя эту команду вместо rebase --onto ..., никаких сбоев из-за собственных слияний с мастером не возникнет - слияния, которые могут потребовать разрешения конфликта, потому что rebase фактически «повторяет» коммиты.

Примечание: Кажется, лучше клонироватьудаленное репо, где история переписывается и вставьте сюда свои собственные ветки, вместо того, чтобы извлекать это удаленное репо «как обычно» в ваше локальное репо, а затем перебазировать свои собственные ветки.Основное преимущество: любой старый материал, который не принадлежит вам, не присутствует во вновь клонированном репо, когда он удаляется или переименовывается в переписанном репо.При извлечении переписанного репо в локальное репо ветви, переименованные в новой истории, приведут к дальнейшему существованию ветвей со старыми именами.

ПРЕДЛАГАЕМАЯ ПРОЦЕДУРА

  • клонирует удаленное хранилище с его переписанной историей, предположительно только те ветви, которые связаны с вашей работой - это помогает при проверке следующих операций.
  • указывает remote add tmp, указывая путь к текущему локальномуrepo.
  • в локальном репо: добавьте тег (например, ownstart ) в начальной точке (точках) ваших ветвей (точке, которая используется совместно с master).
  • извлекайте ваши собственные ветки с этого пульта tmp (некоторые git fetch tmp <branch>:<branch>).Много (дублирующих) коммитов параллельно с мастером ветки может появиться под тегом ownstart.Это исчезнет после следующего шага;в качестве альтернативы вы можете создать новый корень в своем теге ownbranch с помощью grafts & git filter-branch перед выполнением выборки).
  • искать новую соответствующую начальную точку, где ownstart имеет эквивалентный коммит в переписанной истории, и применять свой SHAследующим образом: git replace ownstart SHA.Это создаст поддельное соединение всей вашей локальной работы с этой точки к соответствующей записи в новой истории, и оставшаяся часть истории «ниже» ownstart исчезнет из-за сбоя ссылки.

Примечание 1 : любые журналы после этих операций уже должны показывать желаемую цепочку коммитов (например, с использованием gitk).Однако замененные коммиты не переплавляются вместе: они все еще разделены и теперь имеют общего предка из переписанной истории.Это присуще дизайну и не влияет на (правильную) общую интеграцию вашей собственной работы.Можно (и даже рекомендуется - см. Примечание 2) удалить эти двойники, выполнив git filter-branch -- --master..ownstart --all (это может занять много времени).Это изменит SHA всей вашей работы, но цепочка коммитов вверх по течению не будет затронута.Операция git filter-branch создает резервные ветви.В хвосте справочной страницы filter-branch предлагается операция клонирования для получения нового репо без этих резервных копий (используйте --no-hardlinks при локальном клонировании).Но это превратит все ваши собственные ветви в удаленные отслеживающие устройства при назначении другого источника в восходящем направлении.

Примечание 2 : при выполнении последовательности испытаний любое слияние определенного коммита в моей собственной ветви(из произвольного мастер-коммита) автоматически повторно связывался с соответствующей переписанной исторической фиксацией после выполнения команды git filter-branch, как описано.Это потрясающе.Тем не менее, в другом тесте это слияние было «пропало» отдельно.Его можно привязать к переписанной истории, выполнив команду git replace с SHA, где родительские слияния главной стороны равны соответствующим коммитам главной ветви.Затем git-filter-branch необходимо повторить.

1 голос
/ 12 июля 2011

Да, это возможно. Вы должны увидеть 2 коммита с одинаковыми датой и временем, когда вы делаете git log --all --describe. Вы можете создать скрипт, который будет сбрасывать все ветви, одну за другой, на новые места.

С помощью тегов вы можете удалять и воссоздавать их

Надеюсь, это поможет

...