양방향 미러링
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
요약
양방향 미러링은 충돌을 일으킬 수 있습니다. 양방향 미러링은 두 리포지터리가 서로 pull 하고 push 하도록 구성합니다. 양방향 미러링을 구성한다면 리포지터리가 충돌에 대비하도록 준비합니다. 다운스트림 인스턴스의 push 이벤트 웹훅은 변경 사항을 더 자주 동기화하여 경쟁 조건을 줄이는 데 도움이 됩니다.
히스토리
- 13.9에서 GitLab Premium으로 이동되었습니다.
양방향 미러링은 충돌을 일으킬 수 있습니다.
양방향 미러링은 두 리포지터리가 서로 pull 하고 push 하도록 구성합니다. 어느 리포지터리도 오류 없이 업데이트된다는 보장은 없습니다.
양방향 미러링에서 충돌 줄이기#
양방향 미러링을 구성한다면 리포지터리가 충돌에 대비하도록 준비합니다. 충돌을 줄이도록 구성하고, 충돌이 발생했을 때 해결하는 방법을 정합니다.
- 보호된 브랜치만 미러링합니다. 어느 쪽 원격에서든 미러링된 커밋을 재작성하면 충돌이 발생하고 미러링이 실패합니다.
- 히스토리 재작성으로 인한 충돌을 막으려면 미러링할 브랜치를 두 원격 모두에서 보호합니다.
- push 이벤트 웹훅으로 미러링 지연을 줄입니다. 양방향 미러링은 같은 브랜치에 비슷한 시점으로 만들어진 커밋이 충돌을 일으키는 경쟁 조건을 만듭니다. push 이벤트 웹훅은 이 경쟁 조건을 완화하는 데 도움이 됩니다. 보호된 브랜치만 push 미러링할 때 GitLab의 push 미러링은 분당 한 번으로 속도가 제한됩니다.
- pre-receive 훅을 사용하여 충돌을 방지합니다.
GitLab으로 즉시 pull을 트리거하는 웹훅 구성#
다운스트림 인스턴스의 push 이벤트 웹훅은 변경 사항을 더 자주 동기화하여 경쟁 조건을 줄이는 데 도움이 됩니다.
사전 요구 사항:
다운스트림 인스턴스에서 웹훅을 만들려면 다음과 같이 진행합니다.
-
API범위를 가진 개인 액세스 토큰을 만듭니다. -
상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
-
왼쪽 사이드바에서 Settings > Webhooks를 선택합니다.
-
웹훅 URL을 추가합니다. 이 경우에는 리포지터리 업데이트 후 즉시 pull을 트리거하도록 pull 미러 API 요청을 사용합니다.
https://gitlab.example.com/api/v4/projects/:id/mirror/pull?private_token=<your_access_token> -
토큰을 마스킹합니다.
-
Push Events를 선택합니다.
-
Add Webhook을 선택합니다.
통합을 테스트하려면 Test를 선택하고 GitLab 이 오류 메시지를 반환하지 않는지 확인합니다.
pre-receive 훅을 사용하여 충돌 방지#
이 방법은 Git push 작업이 업스트림 Git 리포지터리로 프록시되므로 push 작업 성능에 부정적인 영향을 줍니다.
이 구성에서는 한쪽 Git 리포지터리가 정본 업스트림 역할을 하고 다른 쪽이
다운스트림 역할을 합니다. 이 서버 측 pre-receive 훅은 커밋을 업스트림
리포지터리에 먼저 push 한 뒤에만 push를 수락합니다. 이 훅은 다운스트림
리포지터리에 설치합니다.
예를 들면 다음과 같습니다.
#!/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패턴과 일치하는 브랜치만 프록시 push 됩니다.
$TARGET_REPO업데이트가 ref 업데이트로 간주되어 Git 이 그에 대한 경고를 표시하므로, 이 스크립트는 Git 훅 격리 환경을 우회합니다.