Skip to content

깃훅 가이드

dictionary-api는 husky 없이, scripts/ 디렉토리의 bash 스크립트를 Gradle 태스크로 .git/hooks/에 직접 동기화하는 방식을 쓴다.

  1. scripts/pre-commit, scripts/commit-msg 파일을 .git/hooks/로 그대로 복사하는 Gradle 태스크를 등록한다.
    build.gradle
    tasks.register('updateGitHooks', Copy) {
    from file('scripts')
    into file('.git/hooks')
    filePermissions {
    unix(0755)
    }
    }
  2. 빌드(compileJava)할 때마다 이 태스크가 자동 실행돼, 훅 스크립트가 바뀌어도 별도 설치 명령 없이 최신 상태로 동기화된다.
    build.gradle
    tasks.named('compileJava') {
    dependsOn 'spotlessApply'
    dependsOn 'updateGitHooks'
    }

pre-commit — 브랜치 보호 + 포맷 검사

Section titled “pre-commit — 브랜치 보호 + 포맷 검사”
scripts/pre-commit
#!/usr/bin/env bash
set -euo pipefail
# master 브랜치는 작업 브랜치를 병합(git merge)하는 용도로만 쓴다 — 여기에 직접 커밋하는 것(일반 커밋,
# --amend, cherry-pick, revert 등)은 막는다. 병합 커밋은 .git/MERGE_HEAD 존재 여부로 구분한다.
current_branch=$(git symbolic-ref --short -q HEAD || true)
merge_head="$(git rev-parse --git-path MERGE_HEAD 2>/dev/null || true)"
if [[ "$current_branch" == "master" ]] && { [[ -z "$merge_head" ]] || [[ ! -f "$merge_head" ]]; }; then
echo "master 브랜치에는 직접 커밋할 수 없습니다." >&2
exit 1
fi
if ! ./gradlew spotlessCheck --quiet; then
echo "Spotless 포맷 검사에 실패했습니다." >&2
echo " './gradlew spotlessApply' 실행 후 다시 커밋하세요." >&2
exit 1
fi
  1. MERGE_HEAD가 없으면서 현재 브랜치가 master면 즉시 차단한다 — 일반 커밋뿐 아니라 --amend, cherry-pick, revert도 여기 걸린다. pre-merge-commit 훅이 없으면 git merge가 이 pre-commit 훅으로 대체 실행되므로, 병합 자체는 MERGE_HEAD가 있어 통과한다.
  2. ./gradlew spotlessCheck로 코딩 컨벤션의 포맷 규칙을 검사한다 — 실패하면 spotlessApply 실행을 안내하고 커밋을 막는다.
  3. 이 훅은 로컬 저장소에서만 작동한다 — 다른 세션의 원격 직접 push나 GitHub PR 병합(원격에서 커밋이 만들어짐)까지는 막지 못한다.

commit-msg — Conventional Commits 형식 검증

Section titled “commit-msg — Conventional Commits 형식 검증”
scripts/commit-msg
#!/usr/bin/env bash
set -euo pipefail
commit_msg_file="$1"
subject_line=$(grep -v '^#' "$commit_msg_file" | grep -v '^$' | head -n1)
# Merge 커밋은 Git이 자동 생성하므로 검사에서 제외한다.
if [[ "$subject_line" =~ ^Merge ]]; then
exit 0
fi
pattern='^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([a-zA-Z0-9_./-]+\))?!?: .+'
if [[ ! "$subject_line" =~ $pattern ]]; then
echo "커밋 메시지가 Conventional Commits 형식이 아닙니다." >&2
echo " 형식: <type>(<scope>): <subject>" >&2
exit 1
fi
  1. git commit -m "제목"으로 만든 메시지의 첫 줄(주석·빈 줄 제외)만 검사한다.
  2. Merge로 시작하는 줄은 검사를 건너뛴다 — git merge가 자동으로 만드는 병합 커밋 메시지 (Merge branch '...')를 예외 처리하기 위함이다.
  3. npm 기반 프로젝트(mintchoco-guid, dictionary-app)의 @commitlint/cli 대신, 정규식 하나로 직접 검증한다 — Node.js 의존성 없이 순수 bash로 동작한다.