双向镜像

Version history
  • Moved to GitLab Premium in 13.9.

警告: 双向镜像可能会导致冲突。

双向镜像配置两个仓库相互拉取和推送。无法保证任一仓库在更新时不会出现错误。

减少双向镜像中的冲突

如果配置了双向镜像,请为冲突做好准备。配置仓库以减少冲突,并在发生冲突时解决它们:

  • 仅镜像受保护的分支。在任一远程仓库上重写任何镜像的提交都会导致冲突和镜像失败。
  • 在两个远程仓库上保护要镜像的分支,以防止因重写历史而导致的冲突。
  • 使用推送事件 webhook减少镜像延迟。双向镜像会创建一个竞争条件,在同一分支上几乎同时进行的提交会导致冲突。推送事件 webhook 可以帮助缓解这种竞争条件。仅镜像受保护的分支时,GitLab 的推送镜像速率限制为每分钟一次。
  • 使用 pre-receive hook 防止冲突

配置 webhook 以触发 GitLab 的即时拉取

下游实例中的推送事件 webhook可以通过更频繁地同步更改来帮助减少竞争条件。

前提条件:

  • 您已在上游极狐GitLab 实例中配置了推送拉取镜像。

在下游实例中创建 webhook:

  1. 创建一个具有 API 范围的个人访问令牌
  2. 在左侧边栏中,选择 搜索或前往 并找到您的项目。
  3. 选择 设置 > Webhooks
  4. 添加 webhook URL,此 URL 使用 Pull Mirror API 请求在仓库更新后触发即时拉取:

    https://gitlab.example.com/api/v4/projects/:id/mirror/pull?private_token=<your_access_token>
    
  5. 选择 Push Events
  6. 选择 Add Webhook

要测试集成,请选择 Test 并确认 GitLab 没有返回错误消息。

使用 pre-receive hook 防止冲突

警告: 此解决方案会对 Git push 操作的性能产生负面影响,因为它们会被代理到上游 Git 仓库。

在此配置中,一个 Git 仓库充当权威的上游,另一个充当下游。此服务器端 pre-receive hook 仅在首先将提交推送到上游仓库后才接受推送。将此 hook 安装在您的下游仓库中。

例如:

#!/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 模式匹配的分支会被代理推送。
  • 该脚本绕过了 Git hook 隔离环境,因为 $TARGET_REPO 的更新被视为引用更新,Git 会显示相关警告。

使用 Git Fusion 与 Perforce Helix 进行镜像

Version history
  • Moved to GitLab Premium in 13.9.

警告: 双向镜像不应作为永久配置使用。有关替代迁移方法,请参阅从 Perforce Helix 迁移

Git Fusion 提供了一个到 Perforce Helix 的 Git 接口。GitLab 可以使用 Perforce Helix 接口来双向镜像项目。如果无法同时迁移重叠的 Perforce Helix 工作区,它可以在从 Perforce Helix 迁移到 GitLab 时提供帮助。

如果您使用 Perforce Helix 进行镜像,请仅镜像受保护的分支。Perforce Helix 拒绝任何重写历史的推送。由于 Git Fusion 的性能限制,应镜像尽可能少的分支。

当您使用 Git Fusion 配置与 Perforce Helix 的镜像时,应使用以下 Git Fusion 设置:

  • 禁用 change-pusher。否则,每次提交都会被重写为由镜像帐户提交,而不是映射到现有的 Perforce Helix 用户或 unknown_git 用户。
  • 如果 GitLab 用户在 Perforce Helix 中不存在,请使用 unknown_git 用户作为提交作者。

相关主题