Синхронизация двух отдельных репозиториев Git - PullRequest
0 голосов
/ 10 мая 2018

Мы должны работать над репо других команд, но по разным причинам мы хотим, чтобы наша разработка не была видна до тех пор, пока она не будет готова к их репо.

Я клонировал их репо, удалил .gitЗатем папка создала новый репо с файлами.Это заставило нас работать, но я не уверен, что сейчас лучший способ объединить изменения из их репо в наше репо.

Есть ли лучшая настройка, в которой мы можем работать изолированно, но у нас нет такого неудобного временина вершине слияния?

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Удалив папку .git, вы удалили историю. Затем, создав новый репо из этих файлов, вы начали новую историю, которая, по мнению git, не связана. Даже если вы совершили коммит до внесения каких-либо изменений, вы все равно создали новый коммит (с идентично совпадающим контентом).

Вы хотите, чтобы репозитории вашей команды сохранили историю вышестоящего репо, чтобы ваши репо знали, как ваши изменения связаны с этой историей, и затем (относительно) легко объединить в вышестоящие изменения. Затем вы контролируете видимость вверх по течению, просто контролируя, что вы толкаете к этому источнику.

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

По-видимому, вы создали свое новое репо таким образом, что у вас есть пульт с именем origin, с которого ваши разработчики клонируют свои локальные репо. (В дальнейшем я назову это origin, а исходный репозиторий, из которого вы сделали первый снимок, я назову upstream.)

Я также предполагаю, что в вашем origin идет активная разработка, так что было бы проблемой просто повторно clone из upstream; и что вы находитесь в точке, где вы хотите интегрировать изменения с upstream в origin.

Первый шаг, работающий с клоном origin, заключается в извлечении истории upstream.

git remote add upstream url/of/upstream/repo
git fetch upstream

Далее вам нужно интегрировать истории. Есть несколько способов сделать это. Наилучшие долгосрочные результаты будут получены при переписывании истории, хотя это требует определенной координации между вашей командой.

В идеале вы должны сказать всем в команде push о своей работе до origin; его не нужно полностью объединять, но все ветви должны быть push ed. После push своей работы они должны отказаться от своих клонов и подождать, пока вы не сообщите им, что перезапись завершена, и в этот момент они создадут новые клоны origin (и, дополнительно, также добавят удаленный upstream). ).

Если этот уровень координации невозможен, переписывание еще можно сделать; но, скорее всего, это будет больше работы для некоторых или для всех разработчиков, так как им придется выполнять собственную миграцию любых изменений, которых не было в origin в то время, когда вы clone d (или сделали ваш последний *) 1039 * до переписывания). В этом случае может быть лучше использовать опцию без перезаписи (подробнее об этом чуть позже).

После того, как fetch отредактировал всю историю своей команды (или реплицировал ее, когда клонировал свое рабочее репо), вам нужно в дальнейшем идентифицировать фиксацию в истории upstream, которая соответствует первоначальной фиксации в вашем репозитории origin. ,

Если это версия с тегами, это может упростить задачу; но я предполагаю, что это было то, что было на master в то время. Но даже в этом случае, если вы знаете, когда вы это сделали, вы сможете отследить правильный коммит и подтвердить с помощью git diff, что он соответствует вашему первоначальному коммиту.

Итак, вы нашли этот коммит, и мы пометили его O на следующем графике; и для удобства вы можете пометить его.

X -- X -- O -- X -- X -- X <--(upstream/master)

o -- A -- B <--(master)(origin/master)
 \
  C <--(someBranch)

Теперь, самое простое, что нужно сделать - это переучить o, так что родителем его замены будет O. Другой вариант, который дает более «чистый» результат, заключается в том, чтобы переопределить родительские значения A и C, заменив o на O. Последнее может быть немного хитрее, но не так сильно, как вы думаете; так что давайте посмотрим, как это сделать. В приведенном выше примере вы можете использовать что-то вроде

 git filter-branch --parent-filter "sed \"s/$(git rev-parse master~2)/$(git rev-parse origin/master~3)/g\"" -- --branches

что должно дать вам

X -- X -- O -- X -- X -- X <--(upstream/master)
          |\
          | A* -- B* <--(master)
           \
            C* <--(someBranch)

o -- A -- B <--(refs/original/refs/heads/master)(origin/master)
 \
  C <--(refs/original/refs/heads/someBranch)

Затем вы можете принудительно подтолкнуть (git push -f) все переписанные ветви к origin или воссоздать origin из нового репо.

Обратите внимание, что в локальном репо, в котором вы выполняли перезапись, будут новые ссылки под original/refs/heads, представляющие местоположения ветвей перед перезаписью.Также обратите внимание, что ссылки на удаленное отслеживание для origin еще не обновлены (пока вы не нажмете принудительное нажатие или пока не удалите пульт дистанционного управления origin и повторно не добавите его с помощью пульта, который отражает перезапись).

Итак ... что если вы решите, что переписать нельзя?Ну, в этом случае вы, вероятно, захотите иметь одно «интеграционное репо», клонированное из origin с добавлением upstream.В репозитории интеграции вы устанавливаете отображение git replace, сообщая git "всякий раз, когда вы сталкиваетесь с объектом o, используйте вместо него объект O".Это "документы над" проблемой.Он может иметь несколько причуд (см. git replace документы), но в идеале вы сможете перестать полагаться на отображение replace (и репозиторий интеграции) через некоторое время.История разработчиков не будет такой чистой, как при переписывании, но не будет необходимости в восстановлении перестроенного репозитория.

Идея в том, что со временем истории будут "Достаточно комбинированный », что мерзавец поймет, что делать без замены.Это будет связано с тем, как рассчитываются базы слияния.Рассмотрим простой случай.

X -- X -- X -- O -- A -- B -- C <--(upstream/master)

o -- D -- E <--(master)

Теперь вы хотите объединить upstream изменения в master.В своем репозитории для интеграции вы сказали

git replace master~2 upstream/master~3

, который мы могли бы нарисовать как

X -- X -- X -- O -- A -- B -- C <--(upstream/master)
               :
               o -- D -- E <--(master)

, поэтому команды git по умолчанию "see"

X -- X -- X -- O -- A -- B -- C <--(upstream/master)
                 \
                  D -- E <--(master)

Значение, есливы говорите

git checkout master
git merge upstream/master

вычисленная база слияния будет O, а git будет "думать", что дает вам

X -- X -- X -- O -- A -- B -- C <--(upstream/master)
                 \             \
                  D ---- E ---- M <--(master)

, что на самом деле

X -- X -- X -- O -- A -- B -- C <--(upstream/master)
               :               \
               o --- D --- E --- M <--(master)

В этом примере master - единственная ветвь, получающая изменения от upstream, и на этом этапе история master возвращается к upstream/master;поэтому в следующий раз при слиянии upstream/master в master база слияния должна быть C, и замена больше не нужна (так что это может быть выполнено в любом клоне, а не в специально установленном наборе).до репо интеграции).

Теперь я упомянул, что история разработчиков не будет такой «чистой», и очевидно, что в конечном состоянии после того, как вы перестанете использовать замену, у нас будет

X -- X -- X -- O -- A -- B -- C <--(upstream/master)
                               \
               o --- D --- E --- M <--(master)

так что "происхождение" D, E и M несколько нарушено.В частности, не очевидно, как M должен быть результатом слияния C в E.Это можно рассматривать как «злое слияние», хотя это не так плохо, как некоторые в том смысле, что слияние по умолчанию (без использования замены) в любом случае вызовет конфликты слияния.

0 голосов
/ 10 мая 2018

Удаление .git было невыгодно.

Снова клонируйте удаленное хранилище. Вы можете добавить дополнительные пульты с git remote add yourrepo http://urlOfYourRepo

Убедитесь, что в репо по умолчанию для push / fetch для ваших несинхронизированных ветвей установлено значение yourrepo: git push -u yourRepo для установки восходящего потока по умолчанию

Вы всегда можете git fetch origin получить изменения удаленного репо в своем репо, а затем объединить их с вашим репо.

С помощью git push origin yourCommit вы можете переместить ваш Commmit (или филиал) в удаленное хранилище.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...