リポジトリのミラーリング

リポジトリミラーリングは、外部ソースとの間でリポジトリのミラーリングを可能にします。 ブランチ、タグ、コミットをリポジトリ間でミラーリングするために使用できます。

GitLabのリポジトリミラーは自動的に更新されます。 手動で最大5分ごとに更新をトリガーすることもできます。

概要

リポジトリのミラーリングは、GitLab以外のリポジトリを使いたいときに便利です。

GitLabがサポートするリポジトリのミラーリングには2種類あります:

  • Push: GitLabリポジトリを別の場所にミラーリングします。
  • Pull: リポジトリを別の場所からGitLabにミラーリングします。

ミラーリポジトリが更新されると、すべての新しいブランチ、タグ、コミットがプロジェクトのアクティビティフィードに表示されます。

少なくともプロジェクトに開発者アクセス権を持つユーザーは、即時アップデートを強制することもできます:

  • ミラーはすでに更新されています。
  • 前回の更新から5分経過していません。

セキュリティ上の理由から、GitLab 12.10 以降では、オリジナルのリポジトリへの URL は、ミラーリングしたプロジェクトのメンテナー権限またはオーナー権限を持つユーザーにのみ表示されます。

ユースケース

以下は、リポジトリミラーリングの使用例です:

  • GitLabに移行したものの、まだプロジェクトを別のソースに残しておく必要がある場合、GitLabへのミラーリング(プル)を設定するだけで、コミット、タグ、ブランチなどの重要な履歴がすべてGitLabインスタンスで利用できるようになります。
  • 別のソースに古いプロジェクトがあり、もうアクティブに使っていないけれどもアーカイブのために削除したくない場合。 その場合、プッシュミラーを作成することで、アクティブなGitLabリポジトリが古い場所に変更をプッシュすることができます。

リモートリポジトリへのプッシュ

既存のプロジェクトでは、以下のようにプッシュ・ミラーリングを設定できます:

  1. プロジェクトの[Settings(設定)]>[Repository(リポジトリ)]に移動し、[Mirroring repositories(リポジトリのミラーリング)]セクションを展開します。
  2. リポジトリのURLを入力します。
  3. Mirror directionドロップダウンからPushを選択します。
  4. 必要に応じて、認証方法ドロップダウンから認証方法を選択します。
  5. 必要に応じて、[ミラー保護ブランチのみ] ボックスをオンにします。
  6. 必要であれば、Keep divergent refsボックスにチェックを入れてください。
  7. Mirrorrepository ボタンをクリックして、設定を保存します。

Repository mirroring push settings screen

プッシュミラーリングが有効になっている場合、ミラーの分岐を防ぐために、ミラーリポジトリに直接コミットのみをプッシュします。 すべての変更は、いつでもミラーリポジトリに反映されます:

リポジトリ内のファイルにプッシュされた変更は、少なくともリモートミラーに自動的にプッシュされます:

  • 受信から5分以内。
  • ミラー保護ブランチのみが有効な場合は1分以内。

ブランチが分岐している場合は、リポジトリのミラーリングセクションでエラーが表示されます。

APIによるプッシュミラーの設定

リモートミラーAPIを使ってプロジェクトのプッシュミラーを作成したり変更したりすることもできます。

保護されたブランチのみをプッシュ

保護したブランチだけを GitLab からリモートリポジトリにプッシュすることもできます。

このオプションを使用するには、リポジトリのミラーを作成するときに、保護されたブランチだけをミラーするチェックボックスをオンにします。

乖離した審判を維持

GitLab 13.0から導入されました

デフォルトでは、リモートミラーの ref がローカルリポジトリから乖離している場合、プッシュ全体が失敗し、何も更新されません。

たとえば、masterdevelopstable のブランチがあるリポジトリがリモートにミラーされた後、ミラー上のdevelop に新しいコミットが追加された場合、次のプッシュは失敗し、masterstableは分岐していないにもかかわらず、古いままになってしまいます。分岐が解決されるまで、どのブランチの変更もミラーできません。

Keep divergent refsオプションを有効にすると、develop ブランチがスキップされ、masterstable を更新できるようになります。ミラーのステータスには、develop が分岐してスキップされたことが反映され、更新失敗とマークされます。

注意: ミラーの作成後、このオプションは現在のところAPIでのみ変更できます。

GitLabからGitHubへのプッシュミラーの設定

GitLabからGitHubにミラーを設定するには、以下の手順に従う必要があります:

  1. public_repo にチェックを入れてGitHub パーソナルアクセストークンを作成します。
  2. gitリポジトリの URLフィールドには、次のフォーマットで入力してください:https://<your_github_username>@github.com/<your_github_group>/<your_github_project>.git.
  3. パスワード欄にGitHubのパーソナルアクセストークンを入力します。
  4. リポジトリのミラーボタンをクリックします。

ミラーされたリポジトリが一覧表示されます。例えば、https://*****:*****@github.com/<your_github_group>/<your_github_project>.git.

リポジトリはすぐにプッシュされます。 強制的にプッシュするには、適切なボタンをクリックしてください。

2FAを有効にしたGitLabインスタンスへのプッシュミラーの設定

  1. 移動先のGitLabインスタンスで、write_repository スコープを持つ個人アクセストークンを作成します。
  2. ソースのGitLabインスタンスで:
    1. gitリポジトリの URLフィールドには、次のフォーマットで入力してください:https://oauth2@<destination host>/<your_gitlab_group_or_name>/<your_gitlab_project>.git.
    2. Passwordフィールドに、移動先のGitLabインスタンスで作成したGitLabパーソナルアクセストークンを入力します。
    3. リポジトリのミラーボタンをクリックします。

リモートリポジトリからのプル

リポジトリのブランチ、タグ、コミットを上流のリポジトリから自動的に更新するように設定できます。

興味のあるリポジトリが別のサーバーにあり、使い慣れた GitLab のインターフェイスを使ってそのコンテンツやアクティビティを閲覧したい場合に便利です。

既存のプロジェクトにミラープルーを設定するには

  1. プロジェクトの[Settings(設定)]>[Repository(リポジトリ)]に移動し、[Mirroring repositories(リポジトリのミラーリング)]セクションを展開します。
  2. リポジトリのURLを入力します。
  3. ミラーの方向ドロップダウンからプルを選択します。
  4. 必要に応じて、認証方法ドロップダウンから認証方法を選択します。
  5. 必要であれば、以下のボックスにチェックを入れてください:
    • 分岐したブランチを上書きします。
    • ミラーアップデートのパイプラインをトリガーします。
    • ミラーで保護されたブランチのみ
  6. Mirrorrepository ボタンをクリックして、設定を保存します。

Repository mirroring pull settings screen - upper part


Repository mirroring pull settings screen - lower part

GitLab はアップストリームリポジトリから変更をプルするように設定されているので、コミットを GitLab 上のリポジトリに直接プッシュすべきではありません。 代わりに、コミットはすべてアップストリームリポジトリにプッシュする必要があります。 アップストリームリポジトリにプッシュされた変更は、GitLab リポジトリにもプルされます:

注意:GitLabリポジトリのブランチを手動で更新した場合、そのブランチは上流から分岐したブランチになり、GitLabは変更が失われないようにこのブランチを自動更新しなくなります。 また、上流リポジトリで削除されたブランチやタグはGitLabリポジトリに反映されないことに注意してください。

どのように動作するか

リポジトリに対してプルミラーリング機能が有効になると、リポジトリはキューに追加されます。

1分間に1回、Sidekiq cronジョブがリポジトリミラーの更新をスケジュールします:

  • 利用可能な容量。 これはSidekiqの設定によって決まります。 GitLab.comについては、GitLab.com Sidekiqの設定を参照してください。
  • キューにあるリポジトリミラーのうち、更新期限が来ているものの数です。 期限が来ているかどうかは、リポジトリミラーが最後に更新されたタイミングと、何回再試行されたかに依存します。

リポジトリミラーは、Sidekiqがそれらを処理できるようになると更新されます。 リポジトリミラーの更新処理が行われた場合:

  • 成功した場合、更新は少なくとも30分待ちで再度キューに入れられます。
  • 失敗した場合 (たとえばブランチがアップストリームから逸脱した場合など)、後で再試行されます。 ミラーは最大 14 回まで失敗する可能性があり、それ以降は更新キューに入れられなくなります。

SSH認証

SSH認証は相互認証です:

  • リポジトリへのアクセスが許可されていることをサーバーに証明する必要があります。
  • サーバーはまたそのサーバーが実在することを証明しなければなりません。

あなたは自分の認証情報をパスワードまたは公開鍵として提供し、もう一方のリポジトリが存在するサーバーはその認証情報を「ホスト鍵」として提供し、そのフィンガープリントを手動で検証する必要があります。

SSH 経由でミラーリングしている (ssh:// URL を使っている) 場合は、次のようにして認証します:

  • HTTPS と同様、パスワードベースの認証。
  • 公開鍵認証:これはパスワード認証よりもセキュリティが高いことが多く、特に相手リポジトリがデプロイ鍵をサポートしている場合に有効です。

始めるには

  1. プロジェクトの[Settings(設定)]>[Repository(リポジトリ)]に移動し、[Mirroring repositories(リポジトリのミラーリング)]セクションを展開します。
  2. ミラーリング用のssh:// URL を入力します。
注:SCPスタイルのURL(つまり、git@example.com:group/project.git)は、現時点ではサポートされていません。

URLを入力すると、ページに2つのボタンが追加されます:

  • ホストキーの検出
  • ホストキーを手動で入力します。

をクリックします:

  • Detect host keysボタンを押すと、GitLabはサーバーからホストキーを取得し、フィンガープリントを表示します。
  • ホストキーを手動で入力ボタンを押すと、ホストキーを貼り付けるフィールドが表示されます。

GitLab.com や他のコードホスティングサイトはフィンガープリントを公開し、チェックできるようにしています:

セルフマネジメントの GitLab を使っている場合や、他のリポジトリのサーバーにアクセスできる場合は、安全にフィンガープリントを集めることができます:

$ cat /etc/ssh/ssh_host*pub | ssh-keygen -E md5 -l -f -
256 MD5:f4:28:9f:23:99:15:21:1b:bf:ed:1f:8e:a0:76:b2:9d root@example.com (ECDSA)
256 MD5:e6:eb:45:8a:3c:59:35:5f:e9:5b:80:12:be:7e:22:73 root@example.com (ED25519)
2048 MD5:3f:72:be:3d:62:03:5c:62:83:e8:6e:14:34:3a:85:1d root@example.com (RSA)
注意:古いバージョンの SSH では、-E md5 を除外する必要があるかもしれません。

リポジトリをミラーリングするとき、GitLab は接続する前に、保存されているホストキーの少なくとも一つが一致することをチェックするようになりました。 これにより、悪意のあるコードがミラーに注入されたり、パスワードが盗まれたりするのを防ぐことができます。

SSH公開キー認証

SSH 公開鍵認証を使うには、Authentication methodドロップダウンからそのオプションを選択する必要があります。 ミラーが作成されると、GitLab は 4096 ビットの RSA 鍵を生成します。この鍵はCopy SSH public keyボタンをクリックしてコピーできます。

Repository mirroring copy SSH public key to clipboard button

その後、公開SSHキーを他のリポジトリの設定に追加する必要があります:

  • もう一方のリポジトリが GitLab でホストされている場合は、公開 SSH キーをデプロイキーとして追加します。
  • 他のリポジトリが別の場所でホストされている場合は、ユーザーのauthorized_keys ファイルにキーを追加する必要があるかもしれません。 公開 SSH キーをすべてファイルに行単位で貼り付けて保存してください。

いつでもキーを変更する必要がある場合は、ミラーを削除して再追加することで新しいキーを生成できます。 ミラーを実行し続けるには、新しいキーでもう一方のリポジトリを更新する必要があります。

注意:生成された鍵はファイルシステムではなく GitLab データベースに保存されます。 そのため、ミラー用の SSH 公開鍵認証は受信前のフックでは使用できません。

分岐ブランチの上書き

GitLab Starter10.6 で導入されました

ローカルブランチとリモートのバージョンが異なっていても、常にリモートのバージョンで更新するように設定できます。

注意:ミラーブランチの場合、このオプションを有効にするとローカルの変更が失われます。

このオプションを使用するには、リポジトリミラーを作成するときに分岐ブランチを上書きするチェックボックスをオンにします。

ミラーで保護されたブランチのみ

GitLab Starter10.3 で導入されました

リモートリポジトリから GitLab に保護ブランチのみをプルミラーすることができます。 保護されていないブランチはミラーされず、分岐する可能性があります。

このオプションを使用するには、リポジトリのミラーを作成するときに、保護されたブランチだけをミラーするチェックボックスをオンにします。

ハード障害

GitLab Starter10.2 で導入されました

ミラーリング処理が14回連続で失敗すると、ハード的に失敗したとマークされます。 このマークは、以下のいずれかに表示されます:

  • プロジェクトのメインダッシュボード。
  • プルミラーの設定ページ。

プロジェクトがハードフェイルされると、そのプロジェクトはミラーリングのためにピックアップされなくなります。 ユーザーは、強制更新によってプロジェクトのミラーリングを再開することができます。

APIを使用した更新のトリガー

GitLab Starter10.3 で導入されました

プルミラーリングは、ポーリングを使って上流に追加された新しいブランチやコミットを検知します。APIでGitLabに通知すると、更新は即座にプルされます。

詳細については、プロジェクトのプルミラーリングプロセスの開始を参照してください。

強制更新

ミラーは自動的に更新されるようにスケジュールされていますが、リポジトリ設定ページのミラーリングリポジトリセクションにある更新ボタンを使用することで、いつでも強制的に更新することができます。

Repository mirroring force update user interface

双方向ミラーリング

注意:双方向ミラーリングは競合を引き起こす可能性があります。

GitLab リポジトリを同じリモートソースからプルしたりプッシュしたりするように設定した場合、どちらのリポジトリも正しく更新される保証はありません。 リポジトリを双方向ミラーリングするように設定した場合は、起こりうるコンフリクトに備えて、誰がどのように解決するかを決めておく必要があります。

ミラーリングされたコミットをどちらかのリモートで書き換えると、コンフリクトが発生し、ミラーリングが失敗します。 これは以下の方法で防ぐことができます:

履歴の書き換えによる競合を防ぐため、両方のリモートでミラーしたいブランチを保護する必要があります。

双方向ミラーリングは、同じブランチに近いタイミングでコミットすると競合が発生するという競合状態も引き起こします。 この競合状態は、Push イベントwebhook を使って GitLab への即時プルをトリガーすることで、ミラーリングの遅延を減らすことで緩和できます。 GitLab からのプッシュミラーリングは、保護されたブランチをプッシュミラーリングする場合のみ、1 分間に 1 回にレートが制限されます。

GitLab への即時プルをトリガーする webhook の設定

アップストリームの GitLab インスタンスでプッシュと プルのミラーを設定済みだとすると、上記のように即座にプルをトリガーするには、ダウンストリームのインスタンスでPush Event Web Hookを設定する必要があります。

そのためには:

  • API のスコープで個人アクセストークンを作成します。
  • 設定 >Webhooksに移動します。
  • Webhook URL を追加します。この場合、リポジトリが更新されたら即座にプルするためにPull Mirror APIリクエストを使用します。

     https://gitlab.example.com/api/v4/projects/:id/mirror/pull?private_token=<your_access_token>
    
  • プッシュイベント]チェックボックスが選択されていることを確認します。
  • Add Webhookボタンをクリックして webhook を保存します。
  • インテグレーションをテストするにはTestボタンをクリックし、GitLabがエラーを返さないことを確認します。

pre-receive フックを使用したコンフリクトの防止

警告: 提案する解決策は、Gitプッシュオペレーションに悪影響を及ぼします。

サーバーサイドのpre-receive フックを使うことで、上流の Git リポジトリにコミットをプッシュした後でプッシュを受け付けるようにすることができます。 この設定では、一方の Git リポジトリが上流、もう一方が下流となります。pre-receive フックは下流のリポジトリにインストールされます。

GitLabサーバーのServer hooksの設定についてはこちらをご覧ください。

pre-receive フックのサンプルを以下に示します。

#!/usr/bin/env bash

# --- Assume only one push mirror target
# Push mirroring remotes are named `remote_mirror_<id>`, this finds the first remote and uses that.
TARGET_REPO=$(git remote | grep -m 1 remote_mirror)

proxy_push()
{
  # --- Arguments
  OLDREV=$(git rev-parse $1)
  NEWREV=$(git rev-parse $2)
  REFNAME="$3"

  # --- Pattern of branches to proxy pushes
  allowlist=$(expr "$branch" : "\(master\)")

  case "$refname" in
    refs/heads/*)
      branch=$(expr "$refname" : "refs/heads/\(.*\)")

      if [ "$allowlist" = "$branch" ]; then
        unset GIT_QUARANTINE_PATH # handle https://git-scm.com/docs/git-receive-pack#_quarantine_environment
        error="$(git push --quiet $TARGET_REPO $NEWREV:$REFNAME 2>&1)"
        fail=$?

        if [ "$fail" != "0" ]; then
          echo >&2 ""
          echo >&2 " Error: updates were rejected by upstream server"
          echo >&2 "   This is usually caused by another repository pushing changes"
          echo >&2 "   to the same ref. You may want to first integrate remote changes"
          echo >&2 ""
          return
        fi
      fi
      ;;
  esac
}

# Allow dual mode: run from the command line just like the update hook, or
# if no arguments are given then run as a hook script
if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
  # Output to the terminal in command line mode - if someone wanted to
  # resend an email; they could redirect the output to sendmail
  # themselves
  PAGER= proxy_push $2 $3 $1
else
  # Push is proxied upstream one ref at a time. Because of this it is possible
  # for some refs to succeed, and others to fail. This will result in a failed
  # push.
  while read oldrev newrev refname
  do
    proxy_push $oldrev $newrev $refname
  done
fi

なお、このサンプルにはいくつかの制限があります:

  • この例は、あなたのユースケースにそのまま当てはまらないかもしれませんし、修正が必要かもしれません。
    • ミラーのさまざまな種類の認証メカニズムについては考慮されていません。
    • 強制アップデート(履歴の書き換え)では動作しません。
    • allowlist パターンにマッチするブランチのみがプロキシプッシュされます。
  • このスクリプトはGitフックの検疫環境を回避します。なぜなら、$TARGET_REPOのアップデートはrefアップデートとみなされ、Gitはそれについて文句を言うからです。

Git Fusion による Perforce Helix のミラーリング

警告:双方向ミラーリングは、恒久的な構成として使用しないでください。 別の移行方法については、「Perforce Helix からの移行」を参照してください。

Git Fusionは Perforce HelixのGitインターフェースを提供し、GitLabでプロジェクトを双方向にミラーリングすることができます。 これは、Perforce HelixからGitLabに移行する際に、重複しているPerforce Helixワークスペースを同時にGitLabに移行できない場合に便利です。

Perforce Helix でミラーリングを使用する場合は、保護されたブランチのみをミラーリングしてください。 Perforce Helix は、履歴を書き換えるようなプッシュを拒否します。 Git Fusion のパフォーマンス制限のため、ミラーリングするブランチは最少数だけにしてください。

Git Fusion 経由で Perforce Helix のミラーリングを設定する場合は、以下の Git Fusion 設定を推奨します:

  • change-pusher そうしないと、すべてのコミットが、既存の Perforce Helix ユーザやunknown_git ユーザにマッピングされるのではなく、ミラーリングアカウントによってコミットされたものとして書き換えられてしまいます。
  • unknown_git ユーザーは、Perforce Helix に GitLab ユーザーが存在しない場合にコミット作成者として使用されます。

GitFusion の設定については、Perforce.comをご覧ください。

トラブルシューティング

プッシュ中にエラーが発生した場合、GitLab はそのリポジトリに “エラー” のハイライトを表示します。 エラーの詳細は、ハイライトテキストにカーソルを合わせることで確認できます。

13:GitHubでエラーコード2のRST_STREAMを受信しました。

GitHub リポジトリにミラーリングしているときに “13:Received RST_STREAM with error code 2” というメッセージが表示される場合は、GitHub の設定で、コミットで使用した自分のメールアドレスを公開するプッシュをブロックするように設定されている可能性があります。 GitHub で自分のメールアドレスを公開するように設定するか、Block command line pushes that expose my emailの設定を無効にしてください。