web-dev-qa-db-ja.com

2つのリモートGitリポジトリを同期するにはどうすればよいですか?

2つのリポジトリURLがあり、両方に同じものが含まれるようにそれらを同期したいと考えています。 Mercurialでは、私がやろうとしていることは次のようになります。

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

これにより、両方のリポジトリに2つのヘッドが作成されます(2つのヘッドを持つことは一般的ではありませんが、同期化のためにこれを行っているため、非インタラクティブにする必要があります。ヘッドはいずれかのリポジトリから手動でマージされ、次に同期が再度実行されます)。

Gitでも同じことをしたいのですが。たとえば、ユーザーの操作なしで、すべての変更を両方のリポジトリに取得し、複数のブランチ/ヘッド/何でも後でマージします。これは、remotes(?)を追加するのではなく、コマンドでURLを使用してこれを実行しようとしています。これには、多数のリポジトリが含まれる可能性があり、それらすべてにエイリアスがあると、スクリプトが複雑になるだけです。

現在、git clone --bar {repo1}を使用してリポジトリを複製していますが、「更新」するのに苦労しています。私はget fetch {repo1}を試しましたが、それでも私の変更が引き下げられていないようです。 git logには、repo1に追加された変更セットはまだ表示されません。

また、Pushclone--mirrorを使用してみましたが、ローカルに存在しないrepo2からのリモートチェンジセットのようですが、両方のリポジトリからの変更を保持する必要があります。 /

これを行う最良の方法は何ですか?

編集:私がやろうとしていることを少し明確にするために...

私は2つのリポジトリー(例えば、BitBucketとGitHub)を持っているので、人々がどちらかにプッシュできるようにしたいと思います(最終的に、1つはGitになり、1つはMercurialになりますが、今のところ、両方をGitにして、物事を単純化するとします)。 2つのリポジトリに両方の変更セットが含まれ、後で手動でマージする必要があるように、2つのリポジトリを「同期」するスクリプトを実行できる必要があります。

結局のところ、これはリポジトリの1つ(たとえばMercurialリポジトリ)と対話するだけでよいことを意味し、私のスクリプトは定期的にマージできるGitの変更を取り込み、その後それらはプッシュバックされます。

Mercurialではtrivial!私は両方のリポジトリからプルし、-f/--forceでプッシュして、複数のヘッドをプッシュできるようにします。その後、誰でもリポジトリの1つを複製し、ヘッドをマージして、プッシュバックできます。私はGitで最も類似したことを行う方法を知りたいです。これは100%非対話型である必要があり、両方のリポジトリをプロセスを無限に繰り返すことができる状態に保つ必要があります(つまり、履歴の書き換えや変更セットの変更などは行われません)。

21
Danny Tuppeny

GitブランチにはMercurialの意味での「頭」はありません。 HEADと呼ばれるものは1つだけあり、これは事実上、現在チェックアウトしているコミットへのシンボリックリンクです。 GitHubのようなホストされたリポジトリの場合、is noコミットがチェックアウトされます—リポジトリの履歴自体があります。 (「ベア」レポと呼ばれます。)

この違いの理由は、Gitブランチ名が完全に任意であることです。それらはリポジトリのコピー間で一致する必要はなく、気まぐれでそれらを作成および破棄できます。[1] GitブランチはPython変数名のようなもので、好きなようにシャッフルして任意の値に固定できます。MercurialブランチはC変数のようなもので、事前に割り当てられた固定メモリ位置を参照してデータを入力します。

したがって、Mercurialをプルすると、ブランチ名は両方のリポジトリで固定された意味のあるものであるため、同じブランチに2つの履歴があります。各履歴の葉は「ヘッド」であり、通常はそれらをマージして単一のヘッドを作成します。

しかし、Gitでは、リモートブランチをフェッチしても、実際にはブランチにまったく影響しません。 masterからOriginブランチをフェッチすると、Origin/masterというブランチに入るだけです。[2] git pull Origin masterは、リモートブランチをOrigin/masterにフェッチしてから、他のブランチを現在のブランチにマージするという2つのステップの単なる砂糖です。ただし、同じ名前である必要はありません。ブランチはdevelopmentまたはtrunkまたはその他の名前で呼び出すことができます。他のブランチをプルしたりマージしたり、他のブランチにプッシュしたりできます。 Gitは関係ありません。

これで問題に戻ります。「2番目の」ブランチヘッドをリモートGitリポジトリにプッシュすることはできません。コンセプトが存在しないためです。あなたcouldマングルされた名前のブランチにプッシュします(bitbucket_master?)が、私の知る限り、リモートのリモートをリモートで更新することはできません。

ただし、マージされていないブランチが両方のリポジトリに公開されている場合は、両方をマージするか、一方をマージしてからもう一方の上にミラーリングする必要があるため、計画はあまり意味がないと思います。 ..その場合、2番目のリポジトリを理由もなく役に立たない状態のままにします。

これを行うことができない理由はありますか?

  1. 正規にするリポジトリを選択します—私はBitBucketを想定しています。それをクローンします。 Originになります。

  2. 他のリポジトリを、たとえばgithubというリモートとして追加します。

  3. 簡単なスクリプトで両方のリモートを定期的にフェッチし、githubブランチをOriginブランチにマージしようとします。マージが失敗した場合は、中止してメールなどを送信してください。マージが簡単な場合は、結果を両方のリモートにプッシュします。

もちろん、機能ブランチですべての作業を行う場合は、これで問題が大幅に軽減されます。 :)


[1]それはさらに良くなります:履歴なしが共通している異なるリポジトリからのブランチをマージできます。個別に開始されたプロジェクトを統合するためにこれを行いました。それらは異なるディレクトリ構造を使用したため、正常に動作します。 GitHubは、ページ機能に同様のトリックを使用します。ページの履歴は、同じリポジトリにあるgh-pagesというブランチに保存されますが、プロジェクトの他の部分と共通する履歴はありません。

[2]これは白い嘘です。ブランチはmasterと呼ばれますが、Originというリモートに属し、スラッシュはそれを参照するための構文です。 Gitにはブランチ名のスラッシュに関する制限がないため、区別が重要になる可能性があります。そのため、Origin/masterという名前のローカルブランチを使用でき、それによりリモートブランチがシャドウされます。

24
Eevee

同様の何かのために、私は両方のリポジトリでwebhookによってトリガーされるこの単純なコードを使用して、GitLabとBitbucketマスターブランチを同期します。

git pull Origin master
git pull gitlab master
git Push Origin master
git Push gitlab master

それはおそらく問題の必要なものではありませんが、1つのブランチだけを同期する必要がある他の誰かにとって役立つかもしれません。

6
Bobík

これが問題のテスト済みソリューションです: 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
4
yorammi

git reset --hard HEADの後にgit fetchを試してください。しかし、私はあなたの目標が何であるかを正確に理解しているとは思いません。フェッチ、リセット、およびプッシュコマンドを実行する前に、個別のリポジトリディレクトリにcdする必要があります。

1
adamdunson

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では、これらのリモートブランチをWebインターフェース経由で表示することはできませんが、-mirrorを使用してクローンを作成するとそれらが存在するため、それらを表示できます。

1
derekv