Git Hook으로 브랜치 이슈 번호를 커밋 메시지에 자동 추가하기
프로젝트를 진행하다 보면 커밋 메시지에 이슈 번호를 함께 남겨야 하는 경우가 많습니다.
예를 들어 브랜치 이름이 다음과 같다면,
feature/#1
커밋 메시지 끝에 자동으로 feature/#1을 붙이고 싶었습니다.
feat: 로그인 API 구현 feature/#1
매번 직접 입력해도 되지만, 반복 작업이기 때문에 Git Hook을 사용해 자동화했습니다.
이번 글에서는 .git/hooks/prepare-commit-msg Hook을 수정해 현재 브랜치 이름에서 이슈 번호를 추출하고, 커밋 메시지에 자동으로 추가하는 방법을 정리합니다.
prepare-commit-msg Hook이란?
Git에는 특정 시점에 자동으로 실행되는 Hook 기능이 있습니다.
그중 prepare-commit-msg는 커밋 메시지가 작성되기 직전에 실행되는 Hook입니다.
즉, 커밋 메시지 파일을 수정할 수 있는 시점에 실행되기 때문에 브랜치 이름이나 이슈 번호를 커밋 메시지에 자동으로 붙이는 용도로 사용할 수 있습니다.
Hook 파일은 다음 경로에 위치합니다.
.git/hooks/prepare-commit-msg
기본적으로 .git/hooks 디렉터리에는 샘플 파일들이 있습니다.
.git/hooks/prepare-commit-msg.sample
이 샘플 파일을 참고해서 prepare-commit-msg 파일을 새로 만들거나 수정하면 됩니다.
목표
이번에 만들고 싶은 동작은 다음과 같습니다.
현재 브랜치: feature/#1
입력한 커밋 메시지: feat: user-service auth 구현
최종 커밋 메시지: feat: user-service auth 구현 feature/#1
단, Merge 커밋이나 Revert 커밋에는 이슈 번호를 붙이지 않도록 했습니다.
Hook 스크립트 작성
.git/hooks/prepare-commit-msg 파일을 다음과 같이 작성했습니다.
#!/bin/bash
# .git/hooks/prepare-commit-msg
COMMIT_MSG_FILE=$1
DEFAULT_COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
CURRENT_BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
ISSUE_TICKET=""
if [[ $CURRENT_BRANCH_NAME =~ (feature|feat)/#([0-9]+) ]]; then
ISSUE_TICKET="${BASH_REMATCH[0]}"
fi
if grep -q -E "^(Merge|Revert)" "$COMMIT_MSG_FILE"; then
# Merge, Revert 커밋은 이슈 번호를 붙이지 않음
echo "$DEFAULT_COMMIT_MSG" > "$COMMIT_MSG_FILE"
else
echo "$DEFAULT_COMMIT_MSG $ISSUE_TICKET" > "$COMMIT_MSG_FILE"
fi
실행 권한 부여
Hook 파일을 작성한 뒤에는 실행 권한을 부여해야 합니다.
chmod +x .git/hooks/prepare-commit-msg
실행 권한이 없으면 Git이 Hook을 실행하지 못할 수 있습니다.
주요 코드 설명
커밋 메시지 파일 읽기
COMMIT_MSG_FILE=$1
DEFAULT_COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
prepare-commit-msg Hook은 첫 번째 인자로 커밋 메시지가 저장된 파일 경로를 전달받습니다.
따라서 $1을 사용해 커밋 메시지 파일 경로를 가져올 수 있습니다.
이후 cat 명령어로 기존 커밋 메시지 내용을 읽어 DEFAULT_COMMIT_MSG 변수에 저장합니다.
현재 브랜치 이름 가져오기
CURRENT_BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
현재 체크아웃된 브랜치 이름을 가져옵니다.
예를 들어 현재 브랜치가 feature/#1이라면 CURRENT_BRANCH_NAME에는 다음 값이 저장됩니다.
feature/#1
정규식으로 이슈 번호 추출하기
if [[ $CURRENT_BRANCH_NAME =~ (feature|feat)/#([0-9]+) ]]; then
ISSUE_TICKET="${BASH_REMATCH[0]}"
fi
이 부분에서는 현재 브랜치 이름이 다음 패턴과 일치하는지 확인합니다.
(feature|feat)/#([0-9]+)
이 정규식은 다음과 같은 브랜치 이름을 매칭합니다.
feature/#1
feat/#42
BASH_REMATCH는 Bash에서 정규식 매칭 결과를 담는 배열입니다.
예를 들어 브랜치 이름이 feature/#1이라면 다음과 같이 값이 들어갑니다.
BASH_REMATCH[0] = feature/#1
BASH_REMATCH[1] = feature
BASH_REMATCH[2] = 1
여기서 BASH_REMATCH[0]은 정규식 전체에 매칭된 값입니다.
따라서 커밋 메시지 끝에 feature/#1 전체를 붙이고 싶다면 다음처럼 사용하면 됩니다.
ISSUE_TICKET="${BASH_REMATCH[0]}"
만약 이슈 번호만 붙이고 싶다면 BASH_REMATCH[2]를 사용할 수 있습니다.
ISSUE_TICKET="#${BASH_REMATCH[2]}"
Merge, Revert 커밋 제외하기
Merge 커밋이나 Revert 커밋에는 Git이 자동으로 커밋 메시지를 생성합니다.
이런 커밋 메시지까지 수정하면 오히려 가독성이 떨어질 수 있기 때문에 제외했습니다.
if grep -q -E "^(Merge|Revert)" "$COMMIT_MSG_FILE"; then
echo "$DEFAULT_COMMIT_MSG" > "$COMMIT_MSG_FILE"
else
echo "$DEFAULT_COMMIT_MSG $ISSUE_TICKET" > "$COMMIT_MSG_FILE"
fi
커밋 메시지가 Merge 또는 Revert로 시작하면 기존 메시지를 그대로 유지합니다.
그 외의 경우에는 커밋 메시지 뒤에 이슈 티켓 정보를 추가합니다.
동작 예시
현재 브랜치가 다음과 같다고 가정합니다.
feature/#1
커밋 메시지를 다음처럼 입력하면,
feat: user-service auth 구현
최종 커밋 메시지는 다음처럼 변경됩니다.
feat: user-service auth 구현 feature/#1
현재 브랜치가 다음과 같다면,
feat/#42
커밋 메시지는 다음과 같이 저장됩니다.
feat: 주문 생성 API 구현 feat/#42
정규식 확인 도구 사용
정규식을 작성할 때는 직접 실행해보는 것보다 시각적으로 확인할 수 있는 도구를 사용하는 것이 편했습니다.
예를 들어 Regexr 같은 도구를 사용하면 작성한 정규식이 어떤 문자열과 매칭되는지, 그룹이 어떻게 나뉘는지 확인할 수 있습니다.
이번 정규식에서는 다음과 같이 그룹이 나뉩니다.
(feature|feat)/#([0-9]+)
전체 매칭: feature/#1
그룹 1: feature
그룹 2: 1
처음에는 특수문자를 기준으로 자동으로 나뉘는 것처럼 보일 수 있지만, 실제로는 정규식에서 괄호 ()로 감싼 부분이 캡처 그룹이 됩니다.
즉, /나 # 같은 특수문자가 기준이 되는 것이 아니라, 정규식에 작성한 괄호가 그룹을 만드는 기준입니다.
정리
Git의 prepare-commit-msg Hook을 사용하면 커밋 메시지가 작성되기 전에 내용을 자동으로 수정할 수 있습니다.
이번 설정에서는 현재 브랜치 이름이 feature/#1, feat/#42 같은 형식일 때 해당 값을 커밋 메시지 끝에 자동으로 추가하도록 구성했습니다.
이를 통해 이슈 번호를 매번 직접 입력하지 않아도 되고, 커밋과 이슈의 연결 관계를 더 쉽게 남길 수 있습니다.
최종적으로 사용한 핵심 흐름은 다음과 같습니다.
현재 브랜치 이름 확인
→ 정규식으로 이슈 번호 패턴 매칭
→ 커밋 메시지 파일 읽기
→ Merge, Revert 커밋 제외
→ 커밋 메시지 끝에 이슈 티켓 추가
작은 자동화지만 커밋 메시지 작성 습관을 일관되게 유지하는 데 도움이 되었습니다.
Reference
'Git' 카테고리의 다른 글
| 머지된 Git 브랜치를 안전하게 정리하는 방법 (0) | 2026.05.24 |
|---|