Подтвердить что ты не робот

Как синхронизировать два удаленных репозитория Git?

У меня есть два URL-адреса репозитория, и я хочу их синхронизировать, чтобы они содержали одно и то же. В Mercurial я пытаюсь сделать следующее:

hg pull {repo1}
hg pull {repo2}
hg push -f {repo1}
hg push -f {repo2}

Это приведет к двум головам в обоих репозиториях (я знаю, что это не так просто, чтобы иметь две головы, но я делаю это для синхронности, и это должно быть неинтерактивным. Головы будут объединены вручную из одного из repos, а затем снова запустить синхронизацию).

Я хотел бы сделать то же самое в Git. Например, без взаимодействия с пользователем, получить все изменения в обоих репозиториях, с несколькими ветвями/головами/тем, которые впоследствии будут объединены. Я пытаюсь сделать это, используя URL-адреса в командах, вместо добавления пультов (?), Так как может быть задействовано несколько репозиториев, и с их псевдонимами все упростит мой script.

В настоящее время я клонирую репо с помощью git clone --bar {repo1}, но я изо всех сил пытаюсь "обновить" его. Я пробовал get fetch {repo1}, но это, кажется, не тянет мои изменения; git log по-прежнему не отображается набор изменений, добавленный в repo1.

Я также попытался использовать --mirror в моих push и clone, но это казалось удаленным наборам изменений из repo2, которые не существовали локально, тогда как мне нужно сохранять изменения от обоих репозиториев:/

Какой лучший способ сделать это?

Изменить: Чтобы сделать это немного яснее, что я пытаюсь сделать...

У меня есть два репозитория (например, BitBucket и GitHub) и хочу, чтобы люди могли нажимать на них (в конечном счете, один будет Git, один будет Mercurial, но пусть предположим, что они оба Git для теперь для упрощения вещей). Мне нужно иметь возможность запускать script, который будет "синхронизировать" два репозитория таким образом, что оба они содержат оба набора изменений и могут потребовать слияния вручную позже.

В конце концов, это означает, что я могу просто взаимодействовать с одним из репозиториев (например, Mercurial), а мой script будет периодически втягивать изменения Git, которые я могу объединить, а затем они будут нажаты назад.

В Mercurial это тривиально! Я просто вытаскиваю из обоих репозиториев и нажимаю -f/--force, чтобы можно было нажать несколько головок. Тогда любой может клонировать один из репозиториев, объединять головы и отталкивать назад. Я хочу знать, как сделать ближайшую аналогичную вещь в Git. Он должен быть на 100% неинтерактивным и должен поддерживать оба РЕПО в состоянии, что процесс может повторяться бесконечно (это означает, что переписывание истории/изменение наборов изменений и т.д.).

4b9b3361

Ответ 1

Git У ветвей нет "головок" в смысле Меркуриона. Существует только одна вещь, называемая HEAD, и она эффективно символическая ссылка на фиксацию, которую вы в настоящее время проверили. В случае размещенных репозиториев, таких как GitHub, проверка фиксации отсутствует - только сама история репозитория. (Вызывается "голым" репо.)

Причиной этой разницы является то, что Git имена ветвей полностью произвольны; они не должны совпадать между копиями репозитория, и вы можете создавать и уничтожать их по прихоти. [1] Разделы Git похожи на имена переменных Python, которые можно перетасовать и придерживаться любого значения по своему усмотрению; Отверстия Mercurial похожи на переменные C, которые относятся к фиксированным ячейкам предварительно распределенной памяти, которые затем заполняются данными.

Итак, когда вы втягиваете Mercurial, у вас есть две истории для одной ветки, потому что имя ветки является фиксированной значимой вещью в обоих хранилищах. Лист каждой истории - это "голова", и вы обычно объединяете их для создания одной головы.

Но в Git выбор удаленной ветки вообще не влияет на вашу ветку. Если вы извлекаете ветвь master из origin, она просто переходит в ветвь с именем origin/master. [2] git pull origin master - это просто тонкий сахар для двух шагов: выбор удаленной ветки в origin/master, а затем слияние этой другой ветки в вашу текущую ветку. Но они не должны иметь одно и то же имя; ваша ветка может быть вызвана development или trunk или что-то еще. Вы можете вытащить или слить в нее любую другую ветку, и вы можете нажать ее на любую другую ветку. Git не заботится.

Что возвращает меня к вашей проблеме: вы не можете нажимать "вторую" ветвь ветки на удаленный репозиторий Git, потому что концепция не существует. Вы можете нажать на ветки с искаженными именами (bitbucket_master?), Но, насколько мне известно, вы не можете удаленно удалять удаленные удаленные объекты.

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

Есть ли причина, по которой вы не можете просто сделать это:

  • Выберите хранилище, чтобы быть каноническим - я предполагаю, что BitBucket. Клонировать его. Он становится origin.

  • Добавить другой репозиторий как удаленный, например, github.

  • Простой script периодически извлекает оба пульта и пытается объединить ветвь github в ветки origin. Если слияние не удалось, отмените и отправьте электронное письмо или что-то еще. Если слияние тривиально, нажмите результат на оба пульта.

Конечно, если вы просто выполняете всю свою работу над ветвями функций, это все становится намного менее проблематичным.:)


[1] Это становится еще лучше: вы можете объединять ветки из разных хранилищ, которые не имеют никакой истории вообще. Я сделал это для консолидации проектов, которые были начаты отдельно; они использовали разные структуры каталогов, поэтому они отлично работают. GitHub использует подобный трюк для своей функции "Страницы": история ваших страниц хранится в ветки с именем gh-pages, которая живет в том же репозитории, но не имеет абсолютно никакой истории, связанной с остальной частью вашего проекта.

[2] Это белая ложь. Ветвь по-прежнему называется master, но она принадлежит удаленному, называемому origin, а косая черта - синтаксис для обращения к ней. Различие может иметь значение, поскольку Git не имеет никаких проблем с косой чертой в именах ветвей, поэтому вы можете иметь локальную ветвь с именем origin/master, и это затеняет удаленную ветвь.

Ответ 2

Для чего-то подобного я использую этот простой код trigerred webhook в обоих хранилищах для синхронизации главной ветки GitLab и Bitbucket:

git pull origin master
git pull gitlab master
git push origin master
git push gitlab master

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

Ответ 3

Здесь протестированное решение проблемы: http://www.tikalk.com/devops/sync-remote-repositories/

Команды для запуска:

#!/bin/bash

# REPO_NAME=<repo>.git
# [email protected]<host>:<project>/$REPO_NAME
# [email protected]<host>:<project>/$REPO_NAME

rm -rf $REPO_NAME
git clone --bare $ORIGIN_URL
cd $REPO_NAME
git remote add --mirror=fetch repo1 $REPO1_URL
git fetch origin --tags git fetch repo1 --tags
git push origin --all git push origin --tags
git push repo1 --all git push repo1 --tags

Ответ 4

Возможно, вы не видели, что выборка действительно работала, когда вы использовали git clone --mirror --bare, потому что по умолчанию git не перечисляет удаленные ветки. Вы можете перечислить их с помощью git branch -a.

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

Однако вы можете попробовать что-то вроде этого:

git clone --bare --mirror --origin thing1 {repo1} repo.git
cd repo.git
git fetch thing2 --mirror
git push thing1 --mirror
git push thing2 --mirror

После того, как это было сделано, вещь1 имела бы все ветки thing2, доступные для слияния в любое время, как удаленные ветки. Вы можете указать удаленные ветки с помощью git branch -a.

В github или bitbucket вы не сможете видеть эти удаленные ветки через веб-интерфейсы, однако вы можете увидеть их, если вы клонируете с --mirror, поэтому они существуют.

Ответ 5

Попробуйте git reset --hard HEAD после git fetch. Однако я не уверен, что я точно понимаю, в чем заключается ваша цель. Вам нужно будет cd в отдельных каталогах репозитория перед запуском команд извлечения, reset и push.