Husky 완벽 가이드 | Git Hooks·Pre-commit·Lint-staged·실전 활용
이 글의 핵심
Husky로 Git Hooks를 관리하는 완벽 가이드. Pre-commit, Pre-push, Lint-staged, Commitlint까지 실전 예제로 정리. Husky·Git Hooks·Pre-commit 중심으로 설명합니다.
이 글의 핵심
Husky로 Git Hooks를 관리하는 완벽 가이드입니다. Pre-commit, Pre-push, Lint-staged, Commitlint까지 실전 예제로 정리했습니다.
실무 경험 공유: Husky를 도입하면서, 린트 에러가 있는 코드가 커밋되는 일이 사라지고 코드 품질이 크게 향상된 경험을 공유합니다.
들어가며: “나쁜 코드가 커밋돼요”
실무에서 마주치는 문제들
린트 에러가 있는 코드가 푸시돼요
수동 확인은 놓치기 쉽습니다. Husky로 자동 검사합니다. 커밋 메시지가 일관적이지 않아요
규칙이 없습니다. Commitlint로 강제합니다. 테스트를 건너뛰고 푸시해요
실수로 빠뜨립니다. Pre-push Hook으로 방지합니다.
1. Husky란?
Git Hooks의 역사와 탄생 배경
Git Hooks는 Git이 처음 공개된 2005년부터 존재했던 기능입니다. .git/hooks/ 디렉터리에 셸 스크립트를 두면, 특정 Git 이벤트(커밋, 푸시, 머지 등)가 발생할 때 자동으로 실행됩니다. 초기에는 서버 관리자가 CI/CD 대신 post-receive 훅으로 자동 배포를 구현하거나, 커밋 메시지 형식을 강제하는 용도로 썼습니다.
문제는 팀 공유였습니다:
.git/hooks/는 저장소에 커밋되지 않음 (.git폴더는 Git이 관리)- 팀원마다 훅을 수동으로 설치해야 함 → 신입이 훅을 모르면 그대로 푸시
- Windows/macOS/Linux 경로·셸 차이 → 크로스 플랫폼 스크립트 작성 어려움
Husky 탄생 (2014년 Typicode 개발):
package.json으로 훅 관리 → npm install 시 자동 설치- Node.js 환경에서 실행 → 크로스 플랫폼 스크립트 작성 용이
- 팀 전체 강제 → 저장소에 커밋되므로 누구든 동일한 훅 적용
클라이언트 훅 vs 서버 훅
Git Hooks는 클라이언트 훅(로컬)과 서버 훅(원격 저장소)으로 나뉩니다.
| 훅 종류 | 실행 위치 | 용도 | Husky 지원 |
|---|---|---|---|
| 클라이언트 훅 | |||
pre-commit | 로컬 | 커밋 전 린트·테스트 | ✅ |
prepare-commit-msg | 로컬 | 커밋 메시지 템플릿 삽입 | ✅ |
commit-msg | 로컬 | 커밋 메시지 검증 | ✅ |
post-commit | 로컬 | 커밋 후 알림 | ✅ |
pre-push | 로컬 | 푸시 전 테스트·빌드 | ✅ |
| 서버 훅 | |||
pre-receive | 서버 | 푸시 거부 (권한 체크) | ❌ |
post-receive | 서버 | 배포 트리거 | ❌ |
update | 서버 | 브랜치별 정책 | ❌ |
Husky는 클라이언트 훅만 지원합니다. 서버 훅은 GitHub/GitLab의 Protected Branches·CI/CD로 대체합니다.
핵심 특징
Husky는 Git Hooks 관리 도구입니다. 주요 장점
- 쉬운 설정: 간단한 명령어 (
npx husky init) - Git Hooks: Pre-commit, Pre-push, Commit-msg 등
- Lint-staged: 변경된 파일만 검사 (성능 최적화)
- 팀 공유: package.json으로 관리 (자동 설치)
- 크로스플랫폼: Windows, macOS, Linux (Node.js 기반)
Husky의 내부 동작
-
설치 시 (
npx husky init):.husky/폴더 생성.git/hooks/에 Husky 로더 스크립트 설치package.json의prepare스크립트에husky추가
-
커밋 시 (
git commit):1. Git이 .git/hooks/pre-commit 실행 2. Husky 로더가 .husky/pre-commit 찾아 실행 3. .husky/pre-commit에서 npx lint-staged 등 실행 4. 스크립트가 exit 0 → 커밋 진행 5. 스크립트가 exit 1 → 커밋 거부 -
팀원 설치 시 (
npm install):prepare스크립트 자동 실행 → Husky 훅 설치- 이미
.husky/파일이 있으므로 즉시 적용
2. 설치 및 기본 설정
설치
npm install -D husky
npx husky init
자동으로 .husky/ 폴더와 pre-commit 파일이 생성됩니다.
.husky/pre-commit
npm test
3. Pre-commit Hook
ESLint + Prettier
# .husky/pre-commit
npm run lint
npm run format:check
전체 파일 검사
# .husky/pre-commit
npm run lint
npm run test
4. Lint-staged
설치
npm install -D lint-staged
.husky/pre-commit
npx lint-staged
package.json
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,css,md}": [
"prettier --write"
]
}
}
5. Pre-push Hook
# .husky/pre-push
npm run test
npm run build
6. Commitlint
설치
npm install -D @commitlint/cli @commitlint/config-conventional
commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'test',
'chore',
],
],
},
};
.husky/commit-msg
npx --no -- commitlint --edit $1
커밋 메시지 형식
feat: add user authentication
fix: resolve login bug
docs: update README
style: format code
refactor: simplify API logic
test: add unit tests
chore: update dependencies
7. 실전 예제: 풀 설정
package.json
{
"scripts": {
"lint": "eslint src",
"lint:fix": "eslint src --fix",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,md}\"",
"format:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx,json,css,md}\"",
"test": "jest",
"prepare": "husky"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write",
"jest --bail --findRelatedTests"
],
"*.{json,css,md}": [
"prettier --write"
]
},
"devDependencies": {
"husky": "^9.0.0",
"lint-staged": "^15.0.0",
"@commitlint/cli": "^18.0.0",
"@commitlint/config-conventional": "^18.0.0"
}
}
.husky/pre-commit
npx lint-staged
.husky/pre-push
npm run test
npm run build
.husky/commit-msg
npx --no -- commitlint --edit $1
8. 실무 함정과 대응 전략
함정 1: --no-verify남용
# ❌ 나쁜 습관: "급해서" 매번 bypass
git commit --no-verify -m "fix: urgent hotfix"
git push --no-verify
문제: 훅을 무력화하면 훅을 만든 의미가 없습니다. 프로덕션에 린트 에러가 배포됩니다.
대응
--no-verify는 정말 긴급한 상황(훅 자체 버그, 외부 서비스 장애)에만- 코드 리뷰에서
--no-verify커밋 발견 시 회고 주제로 다루기 - CI/CD에서 동일한 검사 수행 (훅 우회해도 머지 전 차단)
함정 2: 느린 훅으로 개발 흐름 끊김
# ❌ 전체 테스트 실행 (5분 소요)
# .husky/pre-commit
npm test
npm run build
문제: 커밋 한 번에 5분 대기 → 개발자가 --no-verify 쓰기 시작
대응:
# ✅ 변경된 파일만 테스트
# .husky/pre-commit
npx lint-staged
# package.json
{
"lint-staged": {
"*.{js,ts}": [
"eslint --fix",
"jest --bail --findRelatedTests" // 관련 테스트만
]
}
}
- Pre-commit: 빠른 검사 (린트, 포맷, 관련 테스트)
- Pre-push: 무거운 검사 (전체 테스트, 빌드)
함정 3: CI에서만 실패하는 코드
시나리오: 로컬 훅은 통과했는데 CI에서 실패
# 로컬: 오래된 node_modules
npm test # 통과
# CI: 깨끗한 환경
npm ci && npm test # 실패
원인: 로컬 캐시된 패키지 버전이 다름, .env 파일 차이
대응
- CI와 로컬 훅을 동기화
# .husky/pre-commit npm ci --prefer-offline || npm install npm test - 환경 변수 검증 (
.env.example제공)
함정 4: Windows 경로 문제
# ❌ Unix 스타일 경로 (Windows에서 실패)
# .husky/pre-commit
#!/bin/sh
./scripts/lint.sh
대응:
# ✅ Node.js 스크립트 사용 (크로스 플랫폼)
# .husky/pre-commit
npx lint-staged
node scripts/validate.js
함정 5: Husky가 설치 안 됨 (신입·CI)
증상: 신입 개발자 PC에서 훅이 작동 안 함
원인
npm install --production(devDependencies 제외).git폴더가 없는 경로에서 설치 (Docker 빌드 등)
대응:
// package.json
{
"scripts": {
"prepare": "husky || true" // 실패해도 install은 계속
}
}
- 저장소 clone 후 첫
npm install시 자동 설치 확인 - onboarding 문서에
npx husky install명시
일시적 비활성화 (정당한 사용)
# ✅ 훅 자체를 디버깅할 때
git commit --no-verify -m "debug: test hook bypass"
# ✅ 외부 서비스(lint API) 장애로 훅 실패할 때
HUSKY=0 git commit -m "fix: bypass due to linter service outage"
9. CI/CD 통합
GitHub Actions
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run lint
- run: npm run format:check
- run: npm test
정리 및 체크리스트
핵심 요약
- Husky: Git Hooks 관리
- Pre-commit: 커밋 전 검사
- Lint-staged: 변경된 파일만
- Commitlint: 커밋 메시지 규칙
- Pre-push: 푸시 전 검사
- 팀 공유: package.json
구현 체크리스트
- Husky 설치
- Pre-commit Hook 설정
- Lint-staged 설정
- Commitlint 설정
- Pre-push Hook 설정
- VS Code 통합
- 팀원과 공유
- CI/CD 통합
같이 보면 좋은 글
- ESLint 완벽 가이드
- Prettier 완벽 가이드
- Git 완벽 가이드
이 글에서 다루는 키워드
Husky, Git Hooks, Pre-commit, Lint-staged, Code Quality, Git, Frontend
자주 묻는 질문 (FAQ)
Q. 팀원도 자동으로 설정되나요?
A. 네, npm install 시 자동으로 설정됩니다.
Q. Windows에서도 작동하나요?
A. 네, 크로스플랫폼으로 작동합니다.
Q. Hook을 건너뛸 수 있나요?
A. 네, —no-verify 플래그를 사용하면 됩니다.
Q. 프로덕션에서 사용해도 되나요?
A. 네, 거의 모든 JavaScript 프로젝트에서 사용하고 있습니다.