Git 서버 훅
Offering: GitLab Self-Managed
Git 서버 훅은 GitLab 서버에서 사용자 정의 로직을 실행합니다. Git 서버 훅은 pre-receive, post-receive, update Git 서버 사이드 훅을 사용합니다. GitLab 관리자는 gitaly 명령을 사용하여 서버 훅을 구성합니다.
히스토리
- GitLab 15.6에서 서버 훅에서 Git 서버 훅으로 이름이 변경되었습니다.
Git 서버 훅은 GitLab 서버에서 사용자 정의 로직을 실행합니다. 다음과 같은 Git 관련 작업을 실행하는 데 사용할 수 있습니다:
- 특정 커밋 정책 적용.
- 리포지터리 상태에 따른 작업 수행.
Git 서버 훅은 pre-receive, post-receive, update Git 서버 사이드 훅을 사용합니다.
GitLab 관리자는 gitaly 명령을 사용하여 서버 훅을 구성합니다. 이 명령은 다음도 수행합니다:
- Gitaly 서버 실행에 사용됩니다.
- 여러 서브명령을 제공합니다.
- Gitaly gRPC API에 연결합니다.
gitaly 명령에 액세스할 수 없는 경우 서버 훅의 대안으로 다음이 있습니다:
- 웹훅.
- GitLab CI/CD.
- 사용자 구성 가능한 Git 훅 인터페이스를 위한 푸시 규칙.
GitLab Helm 차트 인스턴스의 경우 Gitaly 차트의 글로벌 서버 훅에 대한 정보를 참조하세요.
Geo는 보조 노드에 서버 훅을 복제하지 않습니다.
사전 요구 사항#
- 리포지터리에 대한 스토리지 이름, Gitaly 구성 파일 경로(Linux 패키지 인스턴스에서 기본값은
/var/opt/gitlab/gitaly/config.toml), 리포지터리 상대 경로. - 훅에서 필요한 언어 런타임 및 유틸리티가 Gitaly를 실행하는 각 서버에 설치되어 있어야 합니다.
리포지터리에 대한 서버 훅 설정#
리포지터리에 대한 서버 훅을 설정하려면:
-
사용자 정의 훅이 포함된 tar 파일을 만듭니다:
-
서버 훅이 예상대로 작동하도록 코드를 작성합니다. Git 서버 훅은 모든 프로그래밍 언어로 작성할 수 있습니다. 상단의 shebang이 언어 유형을 반영하는지 확인합니다. 예를 들어 스크립트가 Ruby인 경우 shebang은 아마도
#!/usr/bin/env ruby일 것입니다.- 단일 서버 훅을 만들려면 훅 유형과 일치하는 이름으로 파일을 만듭니다. 예를 들어
pre-receive서버 훅의 경우 파일명은 확장자 없이pre-receive여야 합니다. - 여러 서버 훅을 만들려면 훅 유형과 일치하는 디렉토리를 만듭니다. 예를 들어
pre-receive서버 훅의 경우 디렉토리 이름은pre-receive.d여야 합니다. 해당 디렉토리에 훅 파일을 넣습니다.
- 단일 서버 훅을 만들려면 훅 유형과 일치하는 이름으로 파일을 만듭니다. 예를 들어
-
서버 훅 파일이 실행 가능하고 백업 파일 패턴(
*~)과 일치하지 않는지 확인합니다. 서버 훅은 tar 파일의 루트에 있는custom_hooks디렉토리에 있어야 합니다. -
tar 명령으로 사용자 정의 훅 아카이브를 만듭니다. 예:
tar -cf custom_hooks.tar custom_hooks.
-
-
필요한 옵션으로
hooks set서브명령을 실행하여 리포지터리에 대한 Git 훅을 설정합니다. 예:cat custom_hooks.tar | sudo -u git -- /opt/gitlab/embedded/bin/gitaly hooks set --storage <storage> --repository <relative path> --config <config path>-
노드에 연결하고
--config플래그에 제공하려면 노드에 유효한 Gitaly 구성 경로가 필요합니다. -
사용자 정의 훅 tar 파일은
stdin을 통해 전달해야 합니다. 예:cat custom_hooks.tar | sudo -u git -- /opt/gitlab/embedded/bin/gitaly hooks set --storage <storage> --repository <relative path> --config <config path>
-
-
Gitaly 클러스터(Praefect)를 사용하는 경우 모든 Gitaly 노드에서
hooks set서브명령을 실행해야 합니다.
서버 훅 코드를 올바르게 구현하면 Git 훅이 다음에 트리거될 때 실행됩니다.
Gitaly 클러스터(Praefect)의 서버 훅#
Gitaly 클러스터(Praefect)를 사용하는 경우 개별 리포지터리가 Praefect의 여러 Gitaly 스토리지에 복제될 수 있습니다. 따라서 훅 스크립트는 리포지터리의 복제본이 있는 모든 Gitaly 노드에 복사해야 합니다. 이를 위해 해당 버전에 대한 사용자 정의 리포지터리 훅을 설정하는 것과 동일한 단계를 따르고 각 스토리지에 대해 반복합니다.
스크립트를 복사할 위치는 리포지터리가 저장된 위치에 따라 달라집니다. 새 리포지터리는 해시 스토리지 경로가 아닌 Praefect에서 생성한 복제본 경로를 사용하여 만들어집니다. 복제본 경로를 식별하려면 -relative-path 옵션을 사용하여 예상되는 GitLab 해시 스토리지 경로를 지정하여 Praefect 리포지터리 메타데이터를 쿼리합니다.
모든 리포지터리에 대한 글로벌 서버 훅 만들기#
모든 리포지터리에 적용되는 Git 훅을 만들려면 글로벌 서버 훅을 설정합니다. 글로벌 서버 훅은 다음에도 적용됩니다:
- 프로젝트 및 그룹 위키 리포지터리. 스토리지 디렉토리 이름은
<id>.wiki.git형식입니다. - 프로젝트 아래의 Design Management 리포지터리. 스토리지 디렉토리 이름은
<id>.design.git형식입니다.
서버 훅 디렉토리 선택#
글로벌 서버 훅을 만들기 전에 해당 디렉토리를 선택해야 합니다.
디렉토리는 gitaly['configuration'][:hooks][:custom_hooks_dir] 아래의 gitlab.rb에 설정됩니다. 다음 중 하나를 선택할 수 있습니다:
- 주석을 해제하여
/var/opt/gitlab/gitaly/custom_hooks디렉토리의 기본 제안을 사용합니다. - 자신의 설정을 추가합니다.
- 디렉토리는
[hooks]섹션 아래의gitaly/config.toml에 설정됩니다. 그러나gitaly/config.toml의 값이 비어 있거나 존재하지 않는 경우 GitLab은gitlab-shell/config.yml의custom_hooks_dir값을 사용합니다. - 기본 디렉토리는
/home/git/gitlab-shell/hooks입니다.
글로벌 서버 훅 만들기#
모든 리포지터리에 대한 글로벌 서버 훅을 만들려면:
- GitLab 서버에서 구성된 글로벌 서버 훅 디렉토리로 이동합니다.
- 구성된 글로벌 서버 훅 디렉토리에서 훅 유형과 일치하는 훅 디렉토리를 만듭니다. 예를 들어
pre-receive서버 훅의 경우 디렉토리 이름은pre-receive.d여야 합니다. - 이 새 디렉토리 내에 서버 훅을 추가합니다. Git 서버 훅은 모든 프로그래밍 언어로 작성할 수 있습니다. 상단의 shebang(
#!)이 언어 유형을 반영하는지 확인합니다. 예를 들어 스크립트가 Ruby인 경우 shebang은 아마도#!/usr/bin/env ruby일 것입니다. - 훅 파일을 실행 가능하게 만들고, Git 사용자가 소유하도록 하며, 백업 파일 패턴(
*~)과 일치하지 않는지 확인합니다.
서버 훅 코드가 제대로 구현된 경우 Git 훅이 다음에 트리거될 때 실행됩니다. 훅은 훅 유형 서브디렉토리에서 파일 이름의 알파벳 순으로 실행됩니다.
리포지터리에 대한 서버 훅 제거#
서버 훅을 제거하려면 빈 tar 파일을 hook set에 전달하여 리포지터리에 훅이 없어야 함을 나타냅니다. 예:
cat empty_hooks.tar | sudo -u git -- /opt/gitlab/embedded/bin/gitaly hooks set --storage <storage> --repository <relative path> --config <config path>
연결된 서버 훅#
GitLab은 서버 훅을 체인으로 실행할 수 있습니다. GitLab은 다음 순서로 서버 훅을 검색하고 실행합니다:
- 내장 GitLab 서버 훅. 이 서버 훅은 사용자가 사용자 정의할 수 없습니다.
<project>.git/custom_hooks/<hook_name>: 프로젝트별 훅. 이 위치는 이전 버전과의 호환성을 위해 유지됩니다.<project>.git/custom_hooks/<hook_name>.d/*: 프로젝트별 훅 위치.<custom_hooks_dir>/<hook_name>.d/*: 편집기 백업 파일을 제외한 모든 실행 가능한 글로벌 훅 파일 위치.
서버 훅 디렉토리에서 훅은:
- 알파벳 순으로 실행됩니다.
- 훅이 0이 아닌 값으로 종료되면 실행이 중단됩니다.
서버 훅에 사용 가능한 환경 변수#
서버 훅에 모든 환경 변수를 전달할 수 있지만 지원되는 환경 변수에만 의존해야 합니다.
다음 GitLab 환경 변수는 모든 서버 훅에 지원됩니다:
| 환경 변수 | 설명 |
|---|---|
GL_ID |
푸시를 시작한 사용자 또는 SSH 키의 GitLab 식별자. 예: user-2234 또는 key-4. |
GL_PROJECT_PATH |
GitLab 프로젝트 경로. |
GL_PROTOCOL |
이 변경에 사용된 프로토콜. http(HTTP를 사용한 Git push), ssh(SSH를 사용한 Git push), 또는 web(기타 모든 작업) 중 하나. |
GL_REPOSITORY |
project- 접두사가 있는 GitLab 프로젝트 ID. 예: project-1234 |
GL_USERNAME |
푸시를 시작한 사용자의 GitLab 사용자 이름. |
다음 Git 환경 변수는 pre-receive 및 post-receive 서버 훅에 지원됩니다:
| 환경 변수 | 설명 |
|---|---|
GIT_ALTERNATE_OBJECT_DIRECTORIES |
격리 환경의 대체 오브젝트 디렉토리. |
GIT_OBJECT_DIRECTORY |
격리 환경의 GitLab 프로젝트 경로. |
GIT_PUSH_OPTION_COUNT |
푸시 옵션의 수. |
GIT_PUSH_OPTION_<i> |
<i>가 0에서 GIT_PUSH_OPTION_COUNT에 정의된 값보다 1 적은 값까지인 특정 푸시 옵션의 값. |
사용자 정의 오류 메시지#
서버 훅이 푸시를 거부할 때 사용자가 왜 거부되었는지 이해하고 문제를 해결하는 데 도움이 되는 명확한 오류 메시지를 제공합니다. 사용자 정의 오류 메시지는 훅이 푸시를 거부할 때 GitLab UI와 사용자의 터미널에 표시됩니다.
사용자 정의 오류 메시지가 없으면 사용자에게 (pre-receive hook declined)와 같은 일반적인 메시지만 표시됩니다. 명확한 오류 메시지는 사용자가 다음을 할 수 있도록 도와줍니다:
- 푸시가 거부된 이유를 이해합니다.
- 관리자에게 연락하지 않고 문제를 해결합니다.
- 지원 요청을 줄입니다.
사용자 정의 오류 메시지를 표시하려면 스크립트가 다음을 수행해야 합니다:
- 사용자 정의 오류 메시지를 스크립트의
stdout또는stderr로 전송합니다. - 각 메시지에
GL-HOOK-ERR:접두사를 붙이고 접두사 앞에 다른 문자가 나타나지 않도록 합니다.
예:
# Bad: Generic message
echo "GL-HOOK-ERR: Commit rejected.";
# Good: Specific message with action
echo "GL-HOOK-ERR: Commit rejected: Commit message must include an issue reference (for example, #1234).";
관련 주제#
문제 해결#
Git 서버 훅으로 작업할 때 다음 문제가 발생할 수 있습니다.
오류: pre-receive hook declined#
사용자가 GitLab 리포지터리에 푸시할 때 (pre-receive hook declined)가 포함된 오류 메시지를 받을 수 있습니다. 예:
! [remote rejected] main (pre-receive hook declined)
error: failed to push some refs to 'https://gitlab.example.com/group/project'
이 오류는 pre-receive 훅이 푸시를 거부했음을 나타냅니다. Pre-receive 훅은 리포지터리에서 참조가 업데이트되기 전에 실행됩니다. Git은 푸시를 거부할 수 있는 세 가지 서버 사이드 훅을 제공합니다:
pre-receive: 참조가 업데이트되기 전에 실행됩니다. 전체 푸시를 거부할 수 있습니다.update: 업데이트되는 브랜치별로 한 번 실행됩니다. 개별 브랜치를 거부할 수 있습니다.post-receive: 모든 참조가 업데이트된 후에 실행됩니다. 푸시를 거부할 수 없지만 훅이 실패하면 오류가 발생할 수 있습니다.
(pre-receive hook declined) 오류는 일반적으로 pre-receive 또는 update 훅에서 발생합니다. 문제를 식별하려면:
-
(pre-receive hook declined)메시지 바로 앞의 출력을 확인합니다. 출력에는 종종 푸시가 거부된 이유에 대한 정보가 포함되어 있습니다. 예:remote: GitLab: The default branch of a project cannot be deleted. ! [remote rejected] main (pre-receive hook declined) -
훅이 실패한 이유에 대한 자세한 내용은 Gitaly 로그를 확인합니다:
sudo grep PreReceiveHook /var/log/gitlab/gitaly/current | jq . -
리포지터리에 사용자 정의 서버 훅이 구성되어 있는 경우 사용자 정의 훅 코드에서 문제를 검토합니다.
다음은 pre-receive 훅 실패의 일반적인 원인입니다:
- 기본 브랜치 보호: 기본 브랜치를 삭제하거나 강제 업데이트하는 푸시가 거부됩니다. 소스 리포지터리의 기본 브랜치가 대상 리포지터리와 다를 때
git push --mirror로 이 상황이 발생합니다. - 푸시 규칙: 커밋 메시지 요구 사항, 파일 크기 제한 또는 작성자 이메일 제한과 같은 구성된 푸시 규칙을 푸시가 위반합니다.
- 사용자 정의 서버 훅: 사용자 정의 서버 훅 스크립트가 푸시를 거부했습니다. 사용자 정의 훅 코드와 오류 메시지를 검토합니다.
- 타임아웃: 훅이 실행되는 데 너무 오래 걸려 종료되었습니다. 타임아웃 오류에 대한 Gitaly 로그를 확인합니다.
- LFS 오브젝트: 필요한 Git LFS 오브젝트가 리포지터리에 없습니다.
사용자가 훅 실패를 이해할 수 있도록 사용자 정의 오류 메시지를 사용하여 푸시가 거부된 이유에 대한 명확한 피드백을 제공하세요. 사용자 정의 오류 메시지는 GitLab UI와 사용자의 터미널에 표시됩니다.
