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

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

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

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

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

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

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

как лучше всего это сделать?

Edit: чтобы было немного яснее, что я пытаюсь сделать...

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

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

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

5 ответов


ветви Git не имеют "голов" в ртутном смысле. Есть только одна вещь, которая называется HEAD, и это фактически символическая ссылка на фиксацию, которую вы в настоящее время проверили. В случае размещенных репозиториев, таких как GitHub, там нет commit проверено-есть только сама история репозитория. (Называется "голым" РЕПО.)

причина этой разницы заключается в том, что имена ветвей 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?), но, насколько мне известно, вы не можете обновлять пульты дистанционного управления удаленно.

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

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

  1. выберите репозиторий для канонического-я предполагаю BitBucket. Клонировать. Он становится origin.

  2. добавить другой репозиторий пульт вызвал, говорят,github.

  3. есть простой скрипт, периодически извлекающий оба пульта и пытающийся объединить github филиал(ы) в origin филиалы. Если слияние не удается, прервать и отправить вам по электронной почте или любой другой. Если слияние тривиально, нажмите результат на оба пульта ДУ.

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


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

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


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

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

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


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

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

#!/bin/bash

# REPO_NAME=<repo>.git
# ORIGIN_URL=git@<host>:<project>/$REPO_NAME
# REPO1_URL=git@<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

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


возможно, вы не видели, что fetch действительно работал, когда вы использовали 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

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

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