正式なドキュメントは英語版であり、この日本語訳はAI支援翻訳により作成された参考用のものです。日本語訳の一部の内容は人間によるレビューがまだ行われていないため、翻訳のタイミングにより英語版との間に差異が生じることがあります。最新かつ正確な情報については、英語版をご参照ください。

双方向ミラーリング

  • プラン: Premium、Ultimate
  • 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated

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

双方向ミラーリングは、2つのリポジトリが互いにプルする、およびプッシュするように設定します。いずれのリポジトリもエラーなしで更新できるという保証はありません。

双方向ミラーリングにおける競合を減らす

双方向ミラーリングを設定する場合、リポジトリを競合に備えて準備します。競合を減らすように設定し、発生した場合にそれらを解決する方法を設定します:

  • 保護ブランチのみをミラーする。いずれかのリモートにあるミラーされたコミットを書き換えると、競合が発生し、ミラーリングが失敗します。
  • 両方のリモートでミラーしたいブランチを保護し、履歴の書き換えによって引き起こされる競合を防ぎます。
  • プッシュイベントWebhookを使用してミラーリングの遅延を減らします。双方向ミラーリングは、同じブランチにほぼ同時に行われたコミットが競合を引き起こす競合状態を作成します。プッシュイベントWebhookは、競合状態を軽減するのに役立ちます。GitLabからのプッシュミラーリングは、保護ブランチのみをプッシュミラーリングする場合、1分間に1回にレート制限されます。
  • 事前受信フックを使用して競合を防ぎます。

すぐにGitLabにプルをトリガーするようにWebhookを設定します

ダウンストリームインスタンス内のプッシュイベントWebhookは、変更をより頻繁に同期することで競合状態を減らすのに役立ちます。

前提条件:

  • アップストリームのGitLabインスタンスで、プッシュおよびプルミラーを設定している必要があります。

ダウンストリームインスタンスでWebhookを作成するには:

  1. APIスコープを持つパーソナルアクセストークンを作成します。

  2. 上部のバーで、検索または移動先を選択して、プロジェクトを見つけます。

  3. 設定 > Webhooksを選択します。

  4. Webhook URLを追加します。これは(この場合)、プルミラーAPIリクエストを使用して、リポジトリ更新後に即座にプルをトリガーするものです:

    https://gitlab.example.com/api/v4/projects/:id/mirror/pull?private_token=<your_access_token>
  5. お使いのトークンをマスクする

  6. Push Eventsを選択します。

  7. Add Webhookを選択します。

インテグレーションをTestするには、Testを選択し、GitLabがエラーメッセージを返さないことを確認します。

事前受信フックを使用して競合を防ぎます

このソリューションは、Gitのプッシュ操作のパフォーマンスに悪影響を及ぼします。これは、操作がアップストリームのGitリポジトリにプロキシされるためです。

この設定では、一方のGitリポジトリが信頼できるアップストリームとして機能し、もう一方はダウンストリームとして機能します。このサーバーサイドのpre-receiveフックは、最初にアップストリームリポジトリにコミットをプッシュした後にのみ、プッシュを受け入れます。このフックをダウンストリームリポジトリにインストールします。

例:

#!/usr/bin/env bash

# --- Assume only one push mirror target
# Push mirroring remotes are named `remote_mirror_<id>`.
# This line 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
        # handle https://git-scm.com/docs/git-receive-pack#_quarantine_environment
        unset GIT_QUARANTINE_PATH
        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. It is possible for some refs
  # to succeed, and others to fail. This results in a failed push.
  while read oldrev newrev refname
  do
    proxy_push $oldrev $newrev $refname
  done
fi

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

  • 変更なしでは、お使いのユースケースで機能しない場合があります:
    • ミラーの異なる種類の認証メカニズムは考慮されていません。
    • 強制更新(履歴の書き換え)では機能しません。
    • allowlistパターンに一致するブランチのみがプロキシプッシュされます。
  • スクリプトは、$TARGET_REPOの更新が参照更新と見なされ、Gitがそれについて警告を表示するため、Gitフック検疫環境を回避します。