27

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

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

これにより、両方のリポジトリで 2 つのヘッドが生成されます (2 つのヘッドを持つことは一般的ではないことはわかっていますが、同期化のためにこれを行っているため、非対話的である必要があります。ヘッドはリポジトリの 1 つから手動でマージされ、次に同期が再度実行されます)。

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

現在、レポのクローンを作成しgit clone --bar {repo1}ていますが、「更新」に苦労しています。試してみましget fetch {repo1}たが、変更が反映されないようです。git logrepo1 に追加された変更セットはまだ表示されません。

私も--mirror自分のpushandcloneで使用してみましたが、両方のリポジトリからの変更を保持する必要があるのに対し、ローカルに存在しない repo2 から変更セットをリモートにしているように見えました:/

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

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

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

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

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

4

6 に答える 6

30

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

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

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

しかし、Git では、リモート ブランチを取得しても、実際にはブランチにはまったく影響しません。masterからブランチをフェッチすると、 .[2] originというブランチに移動するだけです。リモート ブランチを にフェッチしてから、他のブランチを現在のブランチにマージするという 2 つの手順を実行するだけです。ただし、名前が同じである必要はありません。あなたのブランチは、または他のものと呼ばれる可能性があります。他のブランチをそこにプルまたはマージしたり、他のブランチにプッシュしたりできます。Git は気にしません。origin/mastergit pull origin masterorigin/masterdevelopmenttrunk

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

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

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

  1. 正規のリポジトリを選択してください。BitBucket を想定しています。それをクローンします。となりoriginます。

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

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

もちろん、すべての作業をフィーチャー ブランチで行うだけであれば、これはそれほど問題ではなくなります。:)


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

[2] これはうそです。ブランチはまだ と呼ばれていますmasterが、 と呼ばれるリモートに属してoriginおり、スラッシュはそれを参照するための構文です。Git にはブランチ名のスラッシュに関する問題がないため、区別が重要になる可能性があります。そのため、という名前のローカル ブランチを作成origin/masterすると、リモート ブランチがシャドウされます。

于 2013-02-24T22:33:15.687 に答える
6

この問題に対するテスト済みの解決策は次のとおりです: 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
于 2015-11-21T10:30:06.000 に答える
2

を使用したときにフェッチが実際に機能したことを見たことがないかもしれませんgit clone --mirror --bare。デフォルトでは、git はリモート ブランチのリストを表示しないためです。で一覧表示できますgit branch -a

名前のないリモートの構文を完全に理解していませんが、URL からのスキームに基づいてリモートを自動的に追加できます... いずれにせよ、それぞれに一意で一貫した名前を選択すると、おそらく最適に機能します。 repo を使用すると、どのような変更がどこから来たのかを知ることができます

ただし、次のようなことを試すことができます。

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 でクローンを作成すると表示されるため、それらは存在します。

于 2013-02-24T20:38:10.623 に答える
1

git reset --hard HEADの後に試してくださいgit fetch。ただし、あなたの目標が何であるかを正確に理解しているかどうかはわかりません。cdfetch、reset、および push コマンドを実行する前に、別のリポジトリ ディレクトリに移動する必要があります。

于 2013-02-24T20:47:01.733 に答える