Close

Git Hooks

Git 후크는 Git 리포지토리에서 특정 이벤트가 발생할 때마다 자동으로 실행되는 스크립트입니다. Git 후크를 사용하여 Git의 내부 동작을 사용자 지정하고 개발 수명 주기의 주요 시점에서 사용자 지정 가능한 작업을 트리거할 수 있습니다.

커밋 만들기 프로세스에서 실행되는 후크

Git 후크의 일반적인 사용 사례에는 커밋 정책 장려, 리포지토리 상태에 따른 프로젝트 환경 변경, 지속적 통합 워크플로 구현이 포함됩니다. 그러나 스크립트는 무한대로 사용자 지정이 가능하기 때문에 Git 후크를 사용하여 개발 워크플로의 거의 모든 부분을 자동화하거나 최적화할 수 있습니다.

이 문서에서는 Git 후크가 작동하는 방식에 대한 개념 개요부터 시작하겠습니다. 그런 다음 로컬 및 서버 측 리포지토리 모두에서 가장 많이 사용되는 후크를 살펴보겠습니다.


개념 개요


모든 Git 후크는 리포지토리에서 특정 이벤트가 발생할 때 Git이 실행하는 일반 스크립트입니다. 이것을 사용하면 설치와 구성이 아주 쉬워집니다.

후크는 로컬 또는 서버 측 리포지토리에 있을 수 있으며 해당 리포지토리의 작업에 대한 응답으로만 실행됩니다. 이 문서의 뒷부분에서 후크 범주를 구체적으로 살펴보겠습니다. 이 섹션의 나머지 부분에서 설명하는 구성은 로컬 후크와 서버 측 후크 모두에 적용됩니다.

후크 설치

후크는 모든 Git 리포지토리의 .git/hooks 디렉터리에 있습니다. 리포지토리를 초기화하면 Git은 이 디렉터리를 예시 스크립트로 자동으로 채웁니다. .git/hooks를 살펴보면 다음과 같은 파일을 찾을 수 있습니다.

applypatch-msg.sample       pre-push.sample
commit-msg.sample           pre-rebase.sample
post-update.sample          prepare-commit-msg.sample
pre-applypatch.sample       update.sample
pre-commit.sample
데이터베이스
관련 자료

전체 Git 리포지토리를 이동하는 방법

Bitbucket 로고
솔루션 보기

Bitbucket Cloud에서 Git에 대해 알아보기

이것은 사용 가능한 후크 대부분을 나타내지만, .sample 확장자로 인해 기본적으로 실행되지 않습니다. 후크를 “설치"하려면 .sample 확장자를 제거하면 됩니다. 또는 처음부터 새 스크립트를 작성하는 경우 위의 파일 이름 중 하나와 일치하는 파일에서 .sample 확장자를 제외한 새 파일을 추가하기만 하면 됩니다.

예를 들어, 간단한 prepare-commit-msg 후크를 설치해 보겠습니다. .sample 확장자를 이 스크립트에서 제거한 후 파일에 다음을 추가합니다.

#!/bin/sh

echo "# Please include a useful commit message!" > $1

후크는 실행 가능해야 하므로 스크립트를 처음부터 새로 만들려면 스크립트의 파일 권한을 변경해야 할 수도 있습니다. 예를 들어, prepare-commit-msg가 실행 가능한지 확인하려면 다음 명령을 실행합니다.

chmod +x prepare-commit-msg

이제 git commit을 실행할 때마다 기본 커밋 메시지 대신 이 메시지가 표시됩니다. 커밋 메시지 준비 섹션에서 이것이 실제로 어떻게 작동하는지 자세히 살펴보겠습니다. 지금은 Git의 내부 기능 중 일부를 사용자 지정할 수 있다는 사실을 마음껏 즐겨보겠습니다.

기본적으로 제공되는 샘플 스크립트는 각 후크에 전달되는 매개 변수(후크마다 다름)를 문서화하므로 매우 유용한 참조입니다.

스크립팅 언어

기본으로 제공되는 스크립트는 대부분 셸 스크립트와 PERL 스크립트입니다. 그러나 실행 파일로 실행할 수 있는 경우 원하는 스크립팅 언어를 사용할 수 있습니다. 각 스크립트의 셔뱅 라인(#!/bin/sh)은 파일을 해석하는 방법을 정의합니다. 따라서 다른 언어를 사용하려면 인터프리터의 경로로 변경하기만 하면 됩니다.

예를 들어, 셸 명령을 사용하는 대신 prepare-commit-msg 파일에 실행 가능한 Python 스크립트를 작성할 수 있습니다. 다음 후크는 이전 섹션의 셸 스크립트와 동일한 작업을 수행합니다.

#!/usr/bin/env python

import sys, os

commit_msg_filepath = sys.argv[1]
with open(commit_msg_filepath, 'w') as f:
    f.write("# Please include a useful commit message!")

첫 번째 줄이 Python 인터프리터를 가리키도록 어떻게 변경되었는지 살펴보세요. 또한 스크립트에 전달된 첫 번째 인수에 액세스하기 위해 $1를 사용하는 대신 sys.argv[1]를 사용했습니다. (다시 말하지만, 이 내용은 잠시 후에 자세히 설명하겠습니다.)

이것은 가장 편한 언어로 작업할 수 있게 해주기 때문에 Git 후크의 매우 강력한 기능입니다.

후크 범위

후크는 특정 Git 리포지토리에 로컬로 존재하고 git clone을 실행할 때 새 리포지토리로 복사되지 않습니다. 또한 후크는 로컬이기 때문에 리포지토리에 액세스할 수 있는 모든 사용자가 변경할 수 있습니다.

이것은 개발자 팀을 위한 후크를 구성할 때 중요한 영향을 미칩니다. 첫째, 팀원들 사이에서 후크가 최신 상태로 유지되도록 하는 방법을 찾아야 합니다. 둘째, 개발자에게 특정 방식으로 보이는 커밋을 만들도록 강요할 수는 없습니다. 그렇게 하도록 권장할 수만 있습니다.

.git/hooks 디렉터리가 프로젝트의 나머지 부분과 함께 복제되지 않고 버전 제어에 있지도 않기 때문에 개발자 팀의 후크를 관리하는 것은 약간 까다로울 수 있습니다. 이 두 가지 문제에 대한 간단한 해결책은 후크를 실제 프로젝트 디렉터리(.git 디렉터리 위)에 저장하는 것입니다. 이렇게 하면 다른 버전 제어 파일처럼 편집할 수 있습니다. 후크를 설치하려면 .git/hooks에서 후크와 연결되는 심볼릭 링크를 만들거나 후크가 업데이트될 때마다 복사하여 .git/hooks에 붙여넣을 수 있습니다.

커밋 만들기 프로세스에서 실행되는 후크

또한 Git은 자동으로 후크를 쉽게 설치할 수 있도록 하는 템플릿 디렉터리 메커니즘도 제공합니다. 이 템플릿 디렉터리에 포함된 모든 파일과 디렉터리는 .git 디렉터리에 복사됩니다( git init 또는 git clone을 사용할 때마다).

아래 설명된 모든 로컬 후크는 리포지토리 소유자가 변경하거나 완전히 제거할 수 있습니다. 실제로 후크를 사용할지 여부는 전적으로 팀원에게 달려 있습니다. 따라서 Git 후크를 엄격하게 적용되는 개발 정책보다는 편리한 개발자 도구로 생각하는 것이 가장 좋습니다.

즉, 서버 측 후크를 사용하여 일부 표준을 따르지 않는 커밋을 거부할 수 있습니다. 이 내용에 대해서는 문서 뒷부분에서 구체적으로 살펴보겠습니다.

로컬 후크


로컬 후크는 해당 후크가 있는 리포지토리에만 영향을 미칩니다. 이 섹션을 읽으면서 각 개발자는 자신의 로컬 후크를 변경할 수 있으므로 커밋 정책을 적용하는 방법으로 사용할 수는 없다는 점을 기억하세요. 그러나 개발자가 특정 가이드라인을 훨씬 더 쉽게 준수하도록 할 수는 있습니다. 이 섹션에서는 가장 유용한 로컬 후크 6개를 살펴보겠습니다.

  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • post-checkout
  • pre-rebase

처음 4개의 후크는 전체 커밋 수명 주기에 연결할 수 있게 해주며, 마지막 2개의 후크는 git checkoutgit rebase 명령에 대해 각각 몇 가지 추가 작업 또는 안전 검사를 수행할 수 있게 해줍니다.

모든 pre- 후크는 발생하려는 작업을 변경할 수 있게 해주며 post- 후크는 알림에만 사용됩니다.

후크 인수를 구문 분석하고 하위 수준의 Git 명령을 사용하여 리포지토리에 대한 정보를 요청하는 유용한 기법도 살펴보겠습니다.

Pre-Commit

pre-commit 스크립트는 Git이 개발자에게 커밋 메시지를 요청하거나 커밋 개체를 생성하기 전에 git commit을 실행할 때마다 실행됩니다. 이 후크를 사용하여 커밋하려는 스냅샷을 검사할 수 있습니다. 예를 들어, 커밋이 기존 기능을 손상시키지 않는지 확인하는 자동화된 테스트를 실행하고 싶을 수 있습니다.

pre-commit 스크립트에는 인수가 전달되지 않으며 0이 아닌 상태로 종료하면 전체 커밋이 중단됩니다. 기본으로 제공되는 pre-commit 후크의 단순하고 더 자세한 버전을 살펴보겠습니다. 이 스크립트는 git diff-index 명령에서 정의한 대로 공백 오류를 발견하면 커밋을 중단합니다(후행 공백, 공백만 있는 줄, 줄의 첫 들여쓰기 안에 있는 탭 뒤에 따라오는 공백은 기본적으로 오류로 간주됩니다).

#!/bin/sh

# Check if this is the initial commit
if git rev-parse --verify HEAD >/dev/null 2>&1
then
    echo "pre-commit: About to create a new commit..."
    against=HEAD
else
    echo "pre-commit: About to create the first commit..."
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Use git diff-index to check for whitespace errors
echo "pre-commit: Testing for whitespace errors..."
if ! git diff-index --check --cached $against
then
    echo "pre-commit: Aborting commit due to whitespace errors"
    exit 1
else
    echo "pre-commit: No whitespace errors :)"
    exit 0
fi

git diff-index를 사용하려면 색인과 비교할 커밋 참조를 찾아야 합니다. 일반적으로는 HEAD지만 초기 커밋을 만들 때는 HEAD가 없으므로 첫 번째 작업은 이 예외적 사례를 고려하는 것입니다. 인수(HEAD)가 유효한 참조인지 아닌지를 확인하는 git rev-parse --verify로 이 작업을 수행할 수 있습니다. >/dev/null 2>& 1 부분은 git rev-parse의 모든 출력을 자동으로 처리합니다. git diff-index와 함께 사용하기 위해 against 변수에 HEAD 또는 빈 커밋 개체가 저장됩니다. 4b825d... 해시는 빈 커밋을 나타내는 마법의 커밋 ID입니다.

git diff-index --cached 명령은 커밋을 색인과 비교합니다. --check 옵션을 전달하면 변경으로 인해 공백 오류가 발생할 경우 경고를 표시하도록 요청하는 것과 같습니다. 오류가 발생할 경우 종료 상태 1을 반환하여 커밋을 중단하고, 그렇지 않을 경우 0으로 종료하고 커밋 워크플로는 정상적으로 계속됩니다.

이것은 pre-commit 후크의 한 가지 예시일 뿐입니다. 기존 Git 명령어를 사용하여 제시된 커밋에서 생성된 변경 사항에 대해 테스트를 실행하지만, pre-commit에서 다른 스크립트 실행, 타사 테스트 제품군 실행, Lint로 코드 스타일 확인과 같이 원하는 모든 작업을 수행할 수 있습니다.

커밋 메시지 준비

prepare-commit-msg 후크는 pre-commit 후크 이후에 호출되어 텍스트 편집기에 커밋 메시지를 채웁니다. 여기서 스쿼시되거나 병합된 커밋에 대해 자동으로 생성된 커밋 메시지를 변경하면 좋습니다.

prepare-commit-msg 스크립트에 1~3개의 인수가 전달됩니다.

1. 메시지가 포함된 임시 파일의 이름. 이 파일을 현재 위치에서 변경하여 커밋 메시지를 변경합니다.

2. 커밋 유형. message(-m 또는 -F 옵션), template(-t 옵션), merge(커밋이 병합 커밋인 경우) 또는 squash(커밋이 다른 커밋을 스쿼시하는 경우)일 수 있습니다.

3. 관련 커밋의 SHA1 해시. -c, -C, 또는 --amend 옵션이 주어진 경우에만 해당합니다.

pre-commit과 마찬가지로 0이 아닌 상태로 종료하면 커밋이 중단됩니다.

커밋 메시지를 편집하는 간단한 예시를 살펴봤으니 이제 더 유용한 스크립트에 대해 알아보겠습니다. 이슈 추적기를 사용할 때 일반적인 규칙은 각 이슈를 별도의 브랜치에서 해결하는 것입니다. 브랜치 이름에 이슈 번호를 포함하면 prepare-commit-msg 후크를 작성하여 해당 브랜치의 각 커밋 메시지에 자동으로 포함시킬 수 있습니다.

#!/usr/bin/env python

import sys, os, re
from subprocess import check_output

# Collect the parameters
commit_msg_filepath = sys.argv[1]
if len(sys.argv) > 2:
    commit_type = sys.argv[2]
else:
    commit_type = ''
if len(sys.argv) > 3:
    commit_hash = sys.argv[3]
else:
    commit_hash = ''

print "prepare-commit-msg: File: %s\nType: %s\nHash: %s" % (commit_msg_filepath, commit_type, commit_hash)

# Figure out which branch we're on
branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip()
print "prepare-commit-msg: On branch '%s'" % branch

# Populate the commit message with the issue #, if there is one
if branch.startswith('issue-'):
    print "prepare-commit-msg: Oh hey, it's an issue branch."
    result = re.match('issue-(.*)', branch)
    issue_number = result.group(1)

    with open(commit_msg_filepath, 'r+') as f:
        content = f.read()
        f.seek(0, 0)
        f.write("ISSUE-%s %s" % (issue_number, content))

먼저 위의 prepare-commit-msg 후크는 스크립트에 전달되는 모든 매개 변수를 수집하는 방법을 보여줍니다. 그런 다음 git symbolic-ref --short HEAD를 호출하여 HEAD에 해당하는 브랜치 이름을 가져옵니다. 이 브랜치 이름이 issue-로 시작하면 첫 줄에 이슈 번호를 포함하도록 커밋 메시지 파일 콘텐츠를 다시 작성합니다. 따라서 브랜치 이름이 issue-224면 다음과 같은 커밋 메시지가 생성됩니다.

ISSUE-224 

# Please enter the commit message for your changes. Lines starting 
# with '#' will be ignored, and an empty message aborts the commit. 
# On branch issue-224 
# Changes to be committed: 
#   modified:   test.txt

prepare-commit-msg를 사용할 때 한 가지 유의할 점은 사용자가 git commit-m 옵션을 사용하여 메시지를 전달할 때도 실행된다는 것입니다. 즉, 위의 스크립트는 사용자가 편집할 수 없도록 ISSUE-[#] 문자열을 자동으로 삽입합니다. 두 번째 매개 변수(commit_type)가 message와 같은지 확인하여 이 문제를 처리할 수 있습니다.

그러나 -m 옵션이 없는 경우 prepare-commit-msg 후크를 사용하면 메시지가 생성된 후에 사용자가 메시지를 편집할 수 있으므로 커밋 메시지 정책을 적용하는 방법이라기보다는 편리한 스크립트에 가깝습니다. 이를 위해서는 다음 섹션에서 설명하는 commit-msg 후크가 필요합니다.

커밋 메시지

commit-msg 후크는 prepare-commit-msg 후크와 매우 비슷하지만 사용자가 커밋 메시지를 입력한 후에 호출됩니다. 이곳은 개발자에게 메시지가 팀의 표준을 준수하지 않는다고 경고하기에 적합한 장소입니다.

이 후크에 전달되는 유일한 인수는 메시지가 포함된 파일의 이름입니다. 사용자가 입력한 메시지가 마음에 들지 않으면 이 파일을 해당 위치에서 변경하거나(prepare-commit-msg와 마찬가지로) 0이 아닌 상태로 종료하여 커밋을 완전히 중단할 수 있습니다.

예를 들어, 다음 스크립트는 사용자가 이전 섹션에서 prepare-commit-msg 후크가 자동으로 생성한 ISSUE-[#] 문자열을 삭제하지 않았는지 확인합니다.

#!/usr/bin/env python

import sys, os, re
from subprocess import check_output

# Collect the parameters
commit_msg_filepath = sys.argv[1]

# Figure out which branch we're on
branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip()
print "commit-msg: On branch '%s'" % branch

# Check the commit message if we're on an issue branch
if branch.startswith('issue-'):
    print "commit-msg: Oh hey, it's an issue branch."
    result = re.match('issue-(.*)', branch)
    issue_number = result.group(1)
    required_message = "ISSUE-%s" % issue_number

    with open(commit_msg_filepath, 'r') as f:
        content = f.read()
        if not content.startswith(required_message):
            print "commit-msg: ERROR! The commit message must start with '%s'" % required_message
            sys.exit(1)

이 스크립트는 사용자가 커밋을 만들 때마다 호출되지만 커밋 메시지를 확인하는 것 이외의 작업은 수행하지 않아야 합니다. 다른 서비스에 스냅샷이 커밋되었음을 알려야 하는 경우 post-commit 후크를 대신 사용해야 합니다.

Post-Commit

post-commit 후크는 post-msg 후크 바로 다음에 호출됩니다. git commit 작업의 결과를 변경할 수 없으므로 주로 알림 목적으로 사용됩니다.

이 스크립트는 매개 변수를 사용하지 않으며 종료 상태가 커밋에 영향을 주지 않습니다. 대부분의 post-commit 스크립트의 경우 방금 만든 커밋에 액세스할 수 있습니다. git rev-parse HEAD를 사용하여 새 커밋의 SHA1 해시를 가져오거나 git log -1 HEAD를 사용하여 모든 정보를 가져올 수 있습니다.

예를 들어, 스냅샷을 커밋할 때마다 상사에게 이메일을 보내고 싶다면(대부분의 워크플로에서는 이상적이지 않겠지만) 다음과 같은 post-commit 후크를 추가하면 됩니다.

#!/usr/bin/env python

import smtplib
from email.mime.text import MIMEText
from subprocess import check_output

# Get the git log --stat entry of the new commit
log = check_output(['git', 'log', '-1', '--stat', 'HEAD'])

# Create a plaintext email message
msg = MIMEText("Look, I'm actually doing some work:\n\n%s" % log)

msg['Subject'] = 'Git post-commit hook notification'
msg['From'] = 'mary@example.com'
msg['To'] = 'boss@example.com'

# Send the message
SMTP_SERVER = 'smtp.example.com'
SMTP_PORT = 587

session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
session.login(msg['From'], 'secretPassword')

session.sendmail(msg['From'], msg['To'], msg.as_string())
session.quit()

post-commit을 사용하여 로컬 지속적 통합 시스템을 트리거할 수도 있지만 대부분의 경우 post-receive 후크에서 이 작업을 수행하는 것이 좋습니다. 이것은 사용자의 로컬 컴퓨터 대신 서버에서 실행되며 모든 개발자가 코드를 푸시할 때마다 실행됩니다. 따라서 지속적 통합을 수행하기에 훨씬 더 적합한 장소입니다.

Post-Checkout

post-checkout 후크는 post-commit 후크와 매우 비슷하게 작동하지만 git checkout으로 참조를 성공적으로 체크아웃할 때마다 호출됩니다. 이것은 혼란을 야기할 수도 있는 생성된 파일이 있는 작업 디렉터리를 지우는 데 유용합니다.

이 후크는 3개의 매개 변수를 허용하며 종료 상태는 git checkout 명령에 영향을 주지 않습니다.

1. 이전 HEAD의 참조

2. 새 HEAD의 참조

3. 브랜치 체크아웃인지 파일 체크아웃이었는지 알려주는 플래그. 플래그는 각각 10이 됩니다.

Python 개발자에게 흔히 발생하는 문제는 생성된 .pyc 파일이 브랜치를 전환한 후에도 남아 있을 때 발생합니다. 인터프리터는 종종 이 .pyc.py 소스 파일 대신 사용합니다. 혼란을 방지하기 위해 다음 post-checkout 스크립트를 사용하여 새 브랜치를 체크아웃할 때마다 .pyc 파일을 모두 삭제할 수 있습니다.

#!/usr/bin/env python

import sys, os, re
from subprocess import check_output

# Collect the parameters
previous_head = sys.argv[1]
new_head = sys.argv[2]
is_branch_checkout = sys.argv[3]

if is_branch_checkout == "0":
    print "post-checkout: This is a file checkout. Nothing to do."
    sys.exit(0)

print "post-checkout: Deleting all '.pyc' files in working directory"
for root, dirs, files in os.walk('.'):
    for filename in files:
        ext = os.path.splitext(filename)[1]
        if ext == '.pyc':
            os.unlink(os.path.join(root, filename))

후크 스크립트의 현재 작업 디렉터리는 항상 리포지토리의 루트로 설정되므로 os.walk ('.') 호출은 리포지토리의 모든 파일을 반복합니다. 그런 다음 확장자를 확인하여 .pyc 파일이면 삭제합니다.

post-checkout 후크를 사용하여 체크아웃한 브랜치에 따라 작업 디렉터리를 변경할 수도 있습니다. 예를 들어, plugins 브랜치를 사용하여 모든 플러그인을 핵심 코드베이스 외부에 저장할 수 있습니다. 다른 브랜치에서 필요하지 않은 바이너리가 이 플러그인에서 많이 필요한 경우 plugins 브랜치에 있을 때만 선택적으로 구축할 수 있습니다.

Pre-Rebase

pre-rebase 후크는 git rebase가 무언가를 변경하기 전에 호출되므로 심각한 문제가 발생하지 않도록 하는 유용한 장소입니다.

이 후크는 2개의 매개 변수를 사용하며, 시리즈가 포크된 업스트림 브랜치와 rebase되는 브랜치입니다. 현재 브랜치를 rebase할 때 두 번째 매개 변수는 비어 있습니다. rebase를 중단하려면 0이 아닌 상태로 종료합니다.

예를 들어, 리포지토리에서 rebase를 완전히 허용하지 않으려면 다음과 같은 post-rebase 스크립트를 사용할 수 있습니다.

#!/bin/sh

# Disallow all rebasing
echo "pre-rebase: Rebasing is dangerous. Don't do it."
exit 1

이제 git rebase를 실행할 때마다 다음 메시지가 표시됩니다.

pre-rebase: Rebasing is dangerous. Don't do it.
The pre-rebase hook refused to rebase.

더 자세한 예시를 확인하면 포함된 pre-rebase.sample 스크립트를 참조하세요. 이 스크립트는 rebase를 허용하지 않을 시기에 대해 조금 더 지능적입니다. rebase하려는 토픽 브랜치가 이미 메인 라인 브랜치로 가정되는 다음 브랜치에 병합되었는지 확인합니다. 병합되었다면 rebase할 경우 문제가 생길 것이므로 스크립트가 rebase를 중단합니다.

서버 측 후크


서버 측 후크는 서버 측 리포지토리(예: 중앙 리포지토리 또는 개발자의 공개 리포지토리)에 있다는 점을 제외하면 로컬 후크와 동일하게 작동합니다. 공식 리포지토리에 연결되면 일부 서버 측 후크는 특정 커밋을 거부하여 정책을 적용하는 방법으로 사용할 수 있습니다.

이 문서의 나머지 부분에서 다루게 될 서버 측 후크는 3가지가 있습니다.

  • pre-receive
  • 업데이트
  • post-receive

이러한 후크를 사용하면 git push 프로세스의 여러 단계에 반응할 수 있습니다.

서버 측 후크의 출력은 클라이언트 콘솔로 파이프되므로 개발자에게 매우 쉽게 메시지를 보낼 수 있습니다. 하지만 이 스크립트는 실행이 완료될 때까지 터미널의 제어를 반환하지 않으므로 장기적으로 실행되는 작업을 수행할 때 주의해야 합니다.

Pre-Receive

pre-receive 후크는 누군가가 git push를 사용하여 리포지토리로 커밋을 푸시할 때마다 실행됩니다. 이 후크는 원래 리포지토리가 아니라 항상 푸시 대상인 원격 리포지토리에 있어야 합니다.

후크는 참조가 업데이트되기 전에 실행되므로 원하는 개발 정책을 적용하기에 좋은 장소입니다. 푸시를 수행하는 사용자, 커밋 메시지의 형식 또는 커밋에 포함된 변경 사항이 마음에 들지 않으면 거부할 수 있습니다. 개발자가 잘못된 형식의 커밋을 하지 못하게 막을 수는 없지만, pre-receive으로 이러한 커밋을 거부하여 잘못된 형식의 커밋이 공식 코드베이스에 들어가지 못하게 할 수 있습니다.

이 스크립트는 매개 변수를 사용하지 않지만 푸시되는 각 참조는 표준 입력에 있는 별도의 줄에 다음 형식으로 스크립트에 전달됩니다.

<old-value> <new-value> <ref-name>

푸시된 참조를 읽고 출력하는 매우 기본적인 pre-receive 스크립트를 사용하여 이 후크가 어떻게 작동하는지 확인할 수 있습니다.

#!/usr/bin/env python

import sys
import fileinput

# Read in each ref that the user is trying to update
for line in fileinput.input():
    print "pre-receive: Trying to push ref: %s" % line

# Abort the push
# sys.exit(1)

다시 말하지만, 정보가 명령줄 인수 대신 표준 입력을 통해 스크립트에 전달되기 때문에 다른 후크들과는 조금 다릅니다. 원격 리포지토리의 .git/hooks 디렉터리에 위의 스크립트를 배치한 다음 main 브랜치를 푸시하면 콘솔에 다음과 같은 내용이 표시됩니다.

b6b36c697eb2d24302f89aa22d9170dfe609855b 85baa88c22b52ddd24d71f05db31f4e46d579095 refs/heads/main

이러한 SHA1 해시를 일부 하위 수준의 Git 명령과 함께 사용하여 생성하려는 변경 사항을 검사할 수 있습니다. 흔한 사용 사례는 다음과 같습니다.

  • 업스트림 rebase와 관련된 변경 거부
  • 빨리 감기가 아닌 병합 방지
  • 사용자에게 의도한 변경을 수행할 수 있는 올바른 권한이 있는지 확인(주로 중앙 Git 워크플로에 사용됨)

여러 참조가 푸시되는 경우 pre-receive에서 0이 아닌 상태를 반환하면 모두 중단됩니다. 브랜치를 사례별로 수락하거나 거부하려면 update 후크를 대신 사용해야 합니다.

업데이트

update 후크는 pre-receive 이후에 호출되며 거의 동일한 방식으로 작동합니다. 실제로 업데이트되기 전에 호출되지만 푸시된 각 참조에 대해 별도로 호출됩니다. 따라서 사용자가 브랜치를 4개 푸시하려고 하면 update가 4번 실행된다는 뜻입니다. pre-receive와 달리 이 후크는 표준 입력에서 읽을 필요가 없습니다. 대신 다음과 같은 3가지 인수를 허용합니다.

1. 업데이트 중인 참조의 이름

2. 참조에 저장된 이전 개체 이름

3. 참조에 저장된 새 개체 이름

이것은 pre-receive에 전달된 정보와 동일하지만 각 참조에 대해 update가 별도로 호출되므로 일부 참조는 거부하고 다른 참조는 허용할 수 있습니다.

#!/usr/bin/env python

import sys

branch = sys.argv[1]
old_commit = sys.argv[2]
new_commit = sys.argv[3]

print "Moving '%s' from %s to %s" % (branch, old_commit, new_commit)

# Abort pushing only this branch
# sys.exit(1)

위의 update 후크는 브랜치 및 이전/새 커밋 해시를 출력합니다. 원격 리포지토리에 두 개 이상의 브랜치를 푸시하면 각 브랜치마다 print 구문이 실행되는 것을 볼 수 있습니다.

Post-Receive

post-receive 후크는 푸시 작업이 성공한 후에 호출되므로 알림을 수행하기에 좋습니다. 변경 사항이 사용자의 로컬 컴퓨터에만 있는 대신 공개 서버에서 사용할 수 있으므로 대부분의 워크플로에서 post-commit보다 알림을 트리거하기에 더 적합한 장소입니다. 다른 개발자에게 이메일을 보내고 지속적 통합 시스템을 트리거하는 것은 post-receive의 일반적인 사용 사례입니다.

이 스크립트는 매개 변수를 사용하지 않지만 표준 입력을 통해 pre-receive와 동일한 정보를 받습니다.

요약


이 문서에서는 Git 후크를 사용하여 내부 동작을 변경하는 방법과 리포지토리에서 특정 이벤트가 발생할 때 알림을 받는 방법을 알아봤습니다. 후크는 .git/hooks 리포지토리에 있는 일반 스크립트로, 설치와 사용자 지정이 매우 쉽습니다.

또한 가장 일반적인 로컬 후크와 서버 측 후크를 살펴봤습니다. 이러한 후크를 통해 전체 개발 수명 주기에 연결할 수 있습니다. 이제 git push 프로세스뿐만 아니라 커밋 만들기 프로세스의 모든 단계에서 사용자 지정 가능한 작업을 수행하는 방법을 알게 되었습니다. 약간의 스크립팅 지식만 있으면 Git 리포지토리로 상상할 수 있는 거의 모든 작업을 수행할 수 있습니다.


이 문서 공유
다음 토픽

여러분께 도움을 드릴 자료를 추천합니다.

이러한 리소스에 책갈피를 지정하여 DevOps 팀의 유형에 대해 알아보거나 Atlassian에서 DevOps에 대한 지속적인 업데이트를 확인하세요.

도구로 가득한 벽을 사용하여 협업하는 사람들

Bitbucket 블로그

DevOps 일러스트레이션

DevOps 학습 경로

Atlassian 전문가와 함께 하는 Demo Den 기능 데모

Bitbucket Cloud가 Atlassian Open DevOps와 작동하는 방법

DevOps 뉴스레터 신청

Thank you for signing up