Синхронизация 2 репозиториев git - PullRequest
0 голосов
/ 29 июня 2018

Я столкнулся со следующей проблемой и у меня нет идей:

Моя компания не разрешает прямой доступ в интернет для наших разработчиков. Поэтому нам крайне необходим наш собственный репозиторий git. Пока все нормально. Проект, над которым работают наши разработчики, поддерживается сторонней компанией, которая также разрабатывает для нас. Эта компания имеет собственный репозиторий git. У них нет прямого доступа к нашему git-репо, а у нас нет прямого доступа к их. Доступ предоставляется только через уединенный сервер, который может достичь своего репо.

Для лучшего понимания:

Репо моей компании = A, Репо сторонних компаний = B

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

До сих пор моим решением был фрагмент скрипта, который я смог найти здесь:

$ORIGIN_URL=EXTERNAL REPO B
$REPO1_URL=INTERNAL REPO A

/usr/bin/git clone -c http.sslVerify=false --bare $ORIGIN_URL
/usr/bin/git remote add --mirror=fetch repo1 $REPO1_URL
/usr/bin/git -c http.sslVerify=false fetch --all
/usr/bin/git fetch repo1 --tags
/usr/bin/git push origin --all
/usr/bin/git push origin --tags
/usr/bin/git push repo1 --all
/usr/bin/git push repo1 --tags

Проблема в том, что обе компании работают в одних и тех же ветвях (то есть A / fix1 и B / fix1). Я постоянно сталкиваюсь с конфликтами (обновления были отклонены, потому что задний конец ветки находится позади его удаленного (не-перемотка вперед). )).

Я пытаюсь найти какой-нибудь фрагмент сценария, который решит эту проблему для меня и обеих компаний.

Я даже был бы благодарен за несколько советов о том, как разрешить этот конфликт, с которым я сталкиваюсь снова и снова.

Спасибо за помощь

С уважением L.

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

Чтобы все это работало, вам (компании A) и им (компании B) необходимо иметь согласованную точку обмена. Этот клон репозитория Git не обязательно должен быть «хозяином» или «источником всей правды». То есть двое из вас - две компании, которые мы притворяемся на данный момент, не состоят из множества отдельных лиц и / или отдельных клонов - могут относиться к этому различными способами, которые зависят от вас двоих; но вам нужно это как сайт координации. Вы можете разместить его в любом месте, если хотите, чтобы вы оба могли его прочитать, по крайней мере, один из вас может изменить его, и если только один может изменить его, то этот - снова A или B - по крайней мере "прочитал" "доступ к хранилищу, которое публикует другой.

(Однако все проще, если общий клон считается "хозяином" или "источником всей правды", потому что люди плохо зарекомендовали себя в определении реальности при наличии множества различных точек зрения. ?)

Для простоты я в основном собираюсь предположить, что кто-то в каждом из A и B имеет доступ на запись (push) к общему репо. Давайте назовем этот общий репозиторий SR. В остальном это просто подход; см. Марк Адельсбергер ответ для другого.

Чтобы упорядочить вещи, имена веток в SR общего репозитория могут быть довольно просто префиксами: вместо master, develop и т. Д. SR может иметь ветви с именем A/master и B/master, A/develop и B/develop и так далее. Представители компании A - либо люди, работающие на git push, либо машинное обновление, работающее при выборке из SR в какую-то уязвимую точку в пределах A - доставляют A master в SR A/master и так далее. Это довольно легко сделать в Git, потому что в Git есть понятие переименования веток, особенно в направлении выборки.

(Если вы используете push для их обновления, рассмотрите возможность установки ловушки предварительного получения или обновления, которая проверяет, разрешено ли аутентифицированному источнику push-обновления обновлять имя, о котором идет речь. То есть вы бы дали другой логин представителям A и B, а затем проверьте, кто выполняет push: это пользователь A или пользователь B? Если это пользователь A, все имена ветвей должны начинаться с refs/heads/A/. Это позволит избежать случайных перезаписей.)

(Если и А, и В используют теги, вам обоим нужно будет использовать довольно серьезную самодисциплину, чтобы убедиться, что вы не топаете друг друга тегами. Возможно, было бы целесообразно полностью запретить теги внутри SR, никогда выталкивая их из A или B. Это потому, что в то время как Git с радостью переименовывает имена ветвей , любые из --tags операций извлечения или нажатия не переименовывают имена тегов , поэтому, если кто-то в A звонит что-то v1.2, а кто-то в B звонит что-то другое v1.2, вы сталкиваетесь с конфликтом имен тегов. Использование --no-tags позволяет избежать этой головной боли за счет того, что никогда не будет любые теги на СР вообще.)

В этой конкретной настройке это позволяет каждой компании иметь внутреннее зеркало общего репозитория SR. Внутреннее зеркало говорит вам, независимо от того, работаете ли вы в A или B, что они видят: если вы в A, вы проверяете B/master или B/develop, чтобы увидеть их последние версии. Это внутреннее зеркало просто копирует все, что есть в SR. Но он дает вам доступ к общим данным, даже если у вас нет прямого доступа, даже к общему хранилищу SR.

отправить сЧто-то от A до B, работник в A предлагает коммиты, а затем кто-то в A, имеющий соответствующие полномочия, интегрирует эти коммиты в некоторый внутренний репозиторий - возможно, тот, который действует как зеркало, или, возможно, еще один репозиторий. Использование Git поощряет большое количество подобных копий репозитория, и на самом деле это работает очень хорошо. Теперь человек в A, который имеет полномочия, толкает коммиты в SR. Если они приземляются там, человек в A также обновляет доступное для A зеркало, чтобы все программисты в A могли видеть, что эти коммиты доступны для программистов в B. В этот момент A/branch отличается от B/branch на SR. Теперь люди в B могут интегрировать их в свой репозиторий. Как только они это сделают, они пройдут тот же самый танец (см. Ниже), и SR снова получит соответствие A/branch и B/branch.

Когда программисты в B делают какое-то обновление, если программисты в A любят это обновление, они могут включать новые коммиты в свои собственные репозитории, а затем отправлять их в виде обновлений тем же способом уполномоченного лица. Теперь вместо того, чтобы B/branch опережать A/branch, оба синхронизируются.

0 голосов
/ 29 июня 2018

Похоже, вы думаете, что их ветвь - это "та же ветвь", что и ваша ветвь, если она имеет то же имя. Это не обязательно правда. Один из способов взглянуть на это: git никогда не думает о ветвях в двух репозиториях как о "одной и той же ветке"; у него просто есть правила интеграции изменений между репозиториями. В зависимости от того, как вы настраиваете эти правила, вы можете думать о них как о «одной и той же ветке».

Итак, первое - настроить правила по-другому. На самом деле поведение git по умолчанию здесь не так уж плохо; но установка --mirror=fetch на пульте repo1 отменяет настройки по умолчанию, что, вероятно, не помогает. Все немного проще, если мы этого не сделаем. Мы также можем упростить задачу, вручную добавив оба пульта вместо клонирования одного из репозиториев. (В этом нет необходимости; я просто думаю, что все становится немного яснее.)

git init --bare
git remote add external $ORIGIN_URL
git remtoe add internal $REPO1_URL
git fetch --all

Теперь предположим, что у каждого репо есть branch1 и branch2, и оба они расходятся, ваш новый репо выглядит как

       E <--(remotes/external/branch2)
      /
o -- x -- D <--(remotes/internal/branch2)
      \
       x -- A -- B <--(remotes/internal/branch1)
        \
         C <--(remotes/external/branch1)

Отсюда вы можете делиться внешними ветвями с внутренним репозиторием, не беспокоясь о конфликтах имен ветвей, распределяя пространства имен.

git push internal refs/remotes/external/*:refs/heads/external/*

Теперь ваш внутренний репо выглядит как

       E <--(external/branch2)
      /
o -- x -- D <--(branch2)
      \
       x -- A -- B <--(branch1)
        \
         C <--(external/branch1)

Конечно, внешние изменения не интегрированы с внутренними, но это то же самое, что было бы, если бы они использовали разные имена веток в соответствии с вашим первоначальным советом. Ожидается - в какой-то момент кто-то должен объединить внешние изменения с внутренними ветвями (или наоборот), и тогда конфликты должны быть разрешены.

(Конечно, вы можете использовать определенные приемы, чтобы сделать разрешение конфликта слияния настолько безболезненным, насколько это возможно - например, отдать предпочтение недолговечным ветвям и частым инкрементным интеграциям. Но вы не можете полностью устранить их.)

Вы также можете поделиться внутренними изменениями в неинтегрированной форме с внешним репо; например делая что-то вроде

git push external refs/remotes/internal/*:refs/heads/internal/*

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

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

git pull
# resolve conflicts
git push

Поскольку вы должны использовать этот репозиторий-мост, и, тем не менее, вероятно, не хотите выполнять всю работу по интеграции в этом репо, у вас есть дополнительные шаги. И это может раздражать, потому что чем дольше длится цикл выборки / интеграции / отправки, тем больше шансов, что новые изменения появятся после выборки, но до нажатия, что потребует от вас еще одного цикла выборки / интеграции / отправки. Конечно, толчки принимаются или отклоняются на основе ref-by-ref, поэтому со временем это должно сработать (как попытка 1 успешно подталкивает ветвь A, а попытка 2 успешно подталкивает ветви B и C и т. Д.).

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

На хранилище моста

fetch --all
git push external refs/origins/internal/*:refs/heads/*

Это пытается напрямую обновить свои ветки. Некоторые из ссылок могут быть отклонены; все в порядке, вы будете надеяться получить их в следующем цикле.

git push internal refs/origins/external/*:refs/heads/external/*

Это всегда должно быть успешным. Чтобы всегда быть успешным, вы должны быть уверены, что никогда не сделаете внутреннюю фиксацию веток external/*. По этой причине вы можете захотеть использовать ссылку, не относящуюся к ветви (то есть оставить внешние ссылки вне иерархии refs/heads), но не совсем понятно, куда вы их поместите. Вы можете продолжать рассматривать их как ссылки на удаленное отслеживание

git push internal refs/origins/external/*:refs/origins/external/*

Это немного затуманено, поскольку у внутреннего репозитория на самом деле нет пульта с именем external ...

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

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

В этом смысле мне нравится идея помещать внутренние ссылки во внешнее репо и внешние ссылки во внутреннее репо, чтобы разработчики обеих компаний могли видеть оба набора изменений. Но то, что вы не хотите, - это чтобы внешние разработчики фиксировали внутренние ветви или наоборот, потому что тогда интеграции начнут становиться странными, с ветвями вроде rsfs /heads / internal / external / master или чем-то таким же глупым.

...