Решение, которое я имею до сих пор, состоит в том, чтобы использовать команду git bundle
, полагаясь на удаленные ссылки для отслеживания того, что уже есть в другом местоположении, с некоторыми необходимыми шагами, которые я придумал, для переноса этих удаленных ссылок через push / pull , Пусть наше местоположение будет называться site-a, а удаленное местоположение будет называться site-b.
Создание пакета для отправки в удаленное местоположение:
~/work$> git clone $LOCAL_REF_URL --mirror bundler
~/work$> cd bundler
~/work/bundler$> git bundle create ../bundle-site-a-$(date +%Y-%m-%d) --branches --tags --not --remotes=site-b
Рабочий репозиторий может быть удален.
Интеграция пакета из удаленного местоположения:
~/work$> git clone -n $LOCAL_REF_URL bundle-integration
~/work$> cd bundle-integration
~/work/bundle-integration$> git checkout --detach
~/work/bundle-integration$> git fetch origin 'refs/heads/*:refs/heads/*' 'refs/remotes/site-b/*:refs/remotes/site-b/*'
~/work/bundle-integration$> git remote add site-b ../bundle-site-b
~/work/bundle-integration$> git fetch --tags site-b 'refs/heads/*'
- В этот момент выборка сообщает, какие удаленные ветви сайта-b были обновлены информацией из пакета, поэтому вставьте сюда работу, необходимую для интеграции тех, которые имеют соответствующие ветви в нашем расположении; сначала
git fetch . 'refs/remotes/site-b/*:refs/heads/*'
для быстрой пересылки тех, кто может быть одним махом, затем git checkout $BRANCH && git merge site-b/$BRANCH
для остальных: ни одна сторона истории не может быть переписана. Также удалите ветки, которые пакет учел, но больше не содержит.
- Если
git push --tags origin 'refs/heads/*:refs/heads/*' 'refs/remotes/site-b/*:refs/remotes/site-b/*' --prune
полностью завершится успешно, вернитесь; мы сделали
~/work/bundle-integration$> git fetch origin
(обычный)
- Примите во внимание работу, выполненную на вашем месте, которая произошла, когда вы были заняты выполнением предыдущих шагов; это все еще должно быть сделано с помощью слияния (хотя в более обычной идиоме
git checkout $BRANCH && git merge origin/$BRANCH
), за исключением вашей собственной работы по слиянию, которую можно перебазировать, если вы предпочитаете
- Перейти к 8
Теперь можно отказаться от рабочего репозитория интеграции пакетов.
Примечания: шаг 1 не может быть просто зеркальным клоном, так как --mirror не просто предполагает --bare, он форсирует его, что несовместимо с необходимостью выполнять интеграцию позже: даже тривиальное (ускоренное перемещение) git merge операции требуют не обнаженного хранилища. Шаг 3 необходим для того, чтобы «припарковать» HEAD
подальше от любой ветви, в противном случае шаг 4 потерпит неудачу, если и когда он попытается напрямую обновить ветку, на которую указывает HEAD
. Шаг 4 необходим (он не извлекает никакой фиксации), поскольку он установит все необходимые ссылки, поскольку удаленный пакет может не обязательно содержать все ветви (он пропускает те, где он не предоставляет обновления), в то время как в конце мы собираемся обрезать ветки от источника на основе наших собственных ветвей, поэтому мы хотим начать со всех ветвей, которые имеет источник; указание refspecs из этого шага в качестве опции -c для исходного клона вместо этого не работает. Шаг 5 необходим, чтобы git знал, как обновить ссылки в refs/remotes/site-b/*
на шаге 6.
Обновление удаленных ссылок отслеживания, когда удаленное местоположение подтвердило, что им удалось получить содержимое отправленного им пакета:
Это делается, выполнив шаги из «Интеграции пакета из удаленного местоположения», за исключением того, что вы берете отправленный пакет, как будто он приходит из удаленного местоположения; очевидно, в этом случае не требуется никакой работы по интеграции, так как филиалы нашего местоположения обязательно обновлены информацией из пакета.