Commitlint은(는) 무엇을 하나요?
Commitlint 설정과 규칙을 사용하여 커밋 메시지를 Conventional Commits 형식으로 검증합니다.
이 스킬을 사용해야 하는 경우
다음과 같은 경우에 이 스킬을 사용하세요:
- 저장소에 commitlint를 설정할 때
- Commitlint 규칙과 공유 가능한 설정을 구성할 때
- Commitlint를 pre-commit 훅이나 CI/CD 파이프라인에 통합할 때
- Commitlint 설정에서 규칙을 추출하여 커밋 메시지 생성을 위한 LLM 프롬프트를 생성할 때
- 커밋 메시지를 프로그램 방식으로 검증할 때
- Commitlint 설정 또는 유효성 검사 오류를 해결할 때
- Commitlint 규칙 구문과 심각도 수준을 이해할 때
- 저장소에서 commitlint 설정 파일을 감지할 때
핵심 기능
설정 파일 감지
Commitlint는 cosmiconfig를 사용하여 다음 우선순위로 설정 파일을 찾습니다:
전용 설정 파일:
.commitlintrc
.commitlintrc.json
.commitlintrc.yaml
.commitlintrc.yml
.commitlintrc.js
.commitlintrc.cjs
.commitlintrc.mjs
.commitlintrc.ts
.commitlintrc.cts
commitlint.config.js
commitlint.config.cjs
commitlint.config.mjs
commitlint.config.ts
commitlint.config.cts
패키지 파일:
commitlint필드가 있는package.jsoncommitlint필드가 있는package.yaml(PNPM)
설정 형식
JavaScript ES 모듈 (권장):
// commitlint.config.js 또는 commitlint.config.mjs
export default {
extends: ['@commitlint/config-conventional'],
};
TypeScript:
// commitlint.config.ts
import type { UserConfig } from '@commitlint/types';
import { RuleConfigSeverity } from '@commitlint/types';
const config: UserConfig = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [RuleConfigSeverity.Error, 'always', ['feat', 'fix', 'docs']],
},
};
export default config;
JSON:
{
"extends": ["@commitlint/config-conventional"]
}
YAML:
extends:
- "@commitlint/config-conventional"
규칙 설정
규칙은 배열로 구성됩니다: [level, applicability, value]
심각도 수준:
| 수준 | 의미 | TypeScript Enum |
|---|---|---|
| 0 | 비활성화 | RuleConfigSeverity.Disabled |
| 1 | 경고 | RuleConfigSeverity.Warning |
| 2 | 오류 | RuleConfigSeverity.Error |
적용 가능성:
'always'- 규칙이 일치해야 함'never'- 규칙이 일치하지 않아야 함
규칙 예시:
rules: {
// 타입이 열거형에 없으면 오류
'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert']],
// 타입이 비어 있으면 오류
'type-empty': [2, 'never'],
// 제목이 비어 있으면 오류
'subject-empty': [2, 'never'],
// 헤더가 100자를 초과하면 오류
'header-max-length': [2, 'always', 100],
// 제목이 마침표로 끝나면 오류
'subject-full-stop': [2, 'never', '.'],
// 본문 앞에 빈 줄이 없으면 경고
'body-leading-blank': [1, 'always'],
}
일반적인 설정
@commitlint/config-conventional
가장 널리 사용되는 공유 가능한 설정입니다. 기본 오류 수준 규칙:
| 규칙 | 설정 | 통과 예시 | 실패 예시 |
|---|---|---|---|
type-enum | ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test'] | fix: message | foo: message |
type-case | 'lowerCase' | fix: message | FIX: message |
type-empty | never | fix: message | : message |
subject-case | never + ['sentence-case', 'start-case', 'pascal-case', 'upper-case'] | fix: some message | fix: Some Message |
subject-empty | never | fix: message | fix: |
subject-full-stop | never, '.' | fix: message | fix: message. |
header-max-length | 100 | 짧은 헤더 | 100자 초과 헤더 |
body-leading-blank | always (경고) | 본문 앞 빈 줄 | 빈 줄 없음 |
body-max-line-length | 100 | 100자 이하 줄 | 100자 초과 줄 |
footer-leading-blank | always (경고) | 푸터 앞 빈 줄 | 빈 줄 없음 |
footer-max-line-length | 100 | 100자 이하 줄 | 100자 초과 줄 |
전체 설정 스키마
// commitlint.config.js
export default {
// 공유 가능한 설정 확장 (노드 해석을 통해 확인)
extends: ['@commitlint/config-conventional'],
// 커밋 메시지 파싱을 위한 파서 프리셋
parserPreset: 'conventional-changelog-atom',
// 출력 포맷터
formatter: '@commitlint/format',
// 사용자 지정 규칙 (상속된 규칙을 재정의)
rules: {
'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore']],
},
// 특정 커밋을 무시하기 위해 true를 반환하는 함수
// 기본 무시 패턴과 병합됨 (병합 커밋, 되돌리기, 시맨틱 버전 태그)
ignores: [(commit) => commit.includes('WIP')],
// 기본 무시 패턴 사용 여부
// 기본 패턴: 'Merge pull request', 'Revert X', 'v1.2.3' 등
defaultIgnores: true,
// 실패 시 표시되는 사용자 지정 도움말 URL
helpUrl: 'https://example.com/commit-guidelines',
// 프롬프트 구성 (@commitlint/cz-commitlint용)
prompt: {
messages: {},
questions: {
type: {
description: '변경 유형을 선택하세요:',
},
},
},
};
CLI 사용법
설치
# npm
npm install -D @commitlint/cli @commitlint/config-conventional
# yarn
yarn add -D @commitlint/cli @commitlint/config-conventional
# pnpm
pnpm add -D @commitlint/cli @commitlint/config-conventional
일반적인 명령어
# 마지막 커밋 검사
npx commitlint --last
# 특정 범위의 커밋 검사
npx commitlint --from HEAD~5
# 특정 커밋부터 검사
npx commitlint --from abc1234
# 표준 입력에서 메시지 검사
echo "feat: add feature" | npx commitlint
# 파일에서 메시지 검사
npx commitlint < .git/COMMIT_EDITMSG
# 편집 플래그로 검사 (.git/COMMIT_EDITMSG 읽기)
npx commitlint --edit
# 사용자 지정 설정 경로로 검사
npx commitlint --config ./custom-commitlint.config.js
# 확인된 설정 출력
npx commitlint --print-config
# 엄격 모드 (경고가 종료 코드 2가 됨)
npx commitlint --last --strict
종료 코드
| 코드 | 의미 |
|---|---|
| 0 | 성공 (오류 없음) |
| 1 | 린트 오류 발견 |
| 2 | 경고 발견 (엄격 모드 전용) |
| 3 | 오류 발견 (엄격 모드) |
| 9 | 설정 파일 누락 (-g 플래그 사용 시) |
규칙 참조
타입 규칙
| 규칙 | 조건 | 기본 적용 가능성 |
|---|---|---|
type-enum | type이 값에 있는 경우 | always |
type-case | type이 value의 대소문자와 일치하는 경우 | always, 'lower-case' |
type-empty | type이 비어 있는 경우 | never |
type-max-length | type의 길이가 value 이하인 경우 | always, Infinity |
type-min-length | type의 길이가 value 이상인 경우 | always, 0 |
제목 규칙
| 규칙 | 조건 | 기본 적용 가능성 |
|---|---|---|
subject-case | subject이 value의 대소문자와 일치하는 경우 | always |
subject-empty | subject이 비어 있는 경우 | never |
subject-full-stop | subject이 value로 끝나는 경우 | never, '.' |
subject-max-length | subject의 길이가 value 이하인 경우 | always, Infinity |
subject-min-length | subject의 길이가 value 이상인 경우 | always, 0 |
subject-exclamation-mark | subject에 : 앞에 느낌표가 있는 경우 | never |
범위 규칙
| 규칙 | 조건 | 기본 적용 가능성 |
|---|---|---|
scope-enum | scope가 값에 있는 경우 | always, [] |
scope-case | scope가 value의 대소문자와 일치하는 경우 | always, 'lower-case' |
scope-empty | scope가 비어 있는 경우 | never |
scope-max-length | scope의 길이가 value 이하인 경우 | always, Infinity |
scope-min-length | scope의 길이가 value 이상인 경우 | always, 0 |
헤더 규칙
| 규칙 | 조건 | 기본 적용 가능성 |
|---|---|---|
header-case | header가 value의 대소문자와 일치하는 경우 | always, 'lower-case' |
header-full-stop | header가 value로 끝나는 경우 | never, '.' |
header-max-length | header의 길이가 value 이하인 경우 | always, 72 |
header-min-length | header의 길이가 value 이상인 경우 | always, 0 |
header-trim | header에 앞/뒤 공백이 없는 경우 | always |
본문 규칙
| 규칙 | 조건 | 기본 적용 가능성 |
|---|---|---|
body-leading-blank | body가 빈 줄로 시작하는 경우 | always |
body-empty | body가 비어 있는 경우 | never |
body-max-length | body의 길이가 value 이하인 경우 | always, Infinity |
body-max-line-length | body 줄의 길이가 value 이하인 경우 (URL 제외) | always, Infinity |
body-min-length | body의 길이가 value 이상인 경우 | always, 0 |
body-case | body가 value의 대소문자와 일치하는 경우 | always, 'lower-case' |
body-full-stop | body가 value로 끝나는 경우 | never, '.' |
푸터 규칙
| 규칙 | 조건 | 기본 적용 가능성 |
|---|---|---|
footer-leading-blank | footer가 빈 줄로 시작하는 경우 | always |
footer-empty | footer가 비어 있는 경우 | never |
footer-max-length | footer의 길이가 value 이하인 경우 | always, Infinity |
footer-max-line-length | footer 줄의 길이가 value 이하인 경우 | always, Infinity |
footer-min-length | footer의 길이가 value 이상인 경우 | always, 0 |
대소문자 값
대소문자를 확인하는 규칙(*-case)의 경우:
[
'lower-case', // 소문자
'upper-case', // 대문자
'camel-case', // 카멜 케이스
'kebab-case', // 케밥 케이스
'pascal-case', // 파스칼 케이스
'sentence-case', // 문장 케이스
'snake-case', // 스네이크 케이스
'start-case', // 스타트 케이스
]
프로그래밍 방식 사용법
설정 불러오기
import load from '@commitlint/load';
async function getCommitlintConfig() {
const config = await load();
console.log(config.rules);
return config;
}
메시지 검증
import load from '@commitlint/load';
import lint from '@commitlint/lint';
async function validateMessage(message) {
const config = await load();
const result = await lint(message, config.rules);
return {
valid: result.valid,
errors: result.errors,
warnings: result.warnings,
};
}
LLM 통합 패턴
프롬프트 생성을 위한 규칙 추출
Commitlint 설정에서 LLM 친화적인 제약 조건을 생성하세요:
def extract_rules_for_prompt(config: dict) -> str:
"""commitlint 규칙을 LLM 친화적인 형식으로 추출합니다."""
rules = config.get("rules", {})
prompt_parts = []
# type-enum이 있으면 추출
if "type-enum" in rules:
level, applicability, types = rules["type-enum"]
if level > 0 and applicability == "always":
prompt_parts.append(f"허용된 커밋 유형: {', '.join(types)}")
# scope-enum이 있으면 추출
if "scope-enum" in rules:
level, applicability, scopes = rules["scope-enum"]
if level > 0 and applicability == "always":
prompt_parts.append(f"허용된 범위: {', '.join(scopes)}")
# header-max-length가 있으면 추출
if "header-max-length" in rules:
level, applicability, max_len = rules["header-max-length"]
if level > 0:
prompt_parts.append(f"헤더 최대 길이: {max_len}자")
# subject-case가 있으면 추출
if "subject-case" in rules:
level, applicability, cases = rules["subject-case"]
if level > 0 and applicability == "never":
forbidden_cases = [case.replace("-", " ") for case in cases]
prompt_parts.append(f"허용되지 않는 제목 대소문자 스타일: {', '.join(forbidden_cases)}")
return "다음 커밋 메시지 제약 조건을 따르십시오:\n" + "\n".join(prompt_parts)
LLM 생성 커밋 검증
def create_commit_validation_prompt() -> str:
"""커밋 메시지 검증을 위한 LLM 친화적인 프롬프트를 생성합니다."""
return """다음 기준에 따라 이 커밋 메시지의 유효성을 검사하십시오:
1. 메시지가 Conventional Commits 형식(예: type(scope): description)을 따르는가?
2. type이 다음 중 하나인가: feat, fix, docs, style, refactor, test, chore, build, ci, perf, revert?
3. 헤더가 100자를 초과하지 않는가?
4. 제목이 대문자로 시작하지 않는가?
5. 제목이 마침표로 끝나지 않는가?
6. type 뒤에 느낌표가 있으면 안 되는가? (subject-exclamation-mark)
다음 형식으로 응답하십시오:
유효함: true/false
오류: 오류 목록 (있는 경우)
경고: 경고 목록 (있는 경우)
"""
문제 해결
일반적인 오류
| 오류 | 원인 | 해결책 |
|---|---|---|
No commitlint config found | 설정 파일 누락 | 저장소 루트에 .commitlintrc 또는 commitlint.config.js 생성 |
Type must be one of [...] | 잘못된 커밋 타입 | 허용된 타입 사용 (feat, fix, docs 등) |
Subject must not end with full stop | 제목 마침표 | 제목 끝에서 마침표 제거 |
Header must not be longer than 100 characters | 헤더가 너무 김 | 헤더를 100자 이내로 줄이기 |
scope must be one of [...] | 허용되지 않은 범위 | 구성된 범위 값 사용 |
Could not resolve config | 모듈 해결 오류 | @commitlint/cli 및 필요한 공유 설정 설치 확인 |
디버깅
# 확인된 설정 확인
npx commitlint --print-config
# 자세한 로그 출력 (환경 변수)
DEBUG=commitlint:* npx commitlint --last
# 특정 규칙 테스트
npx commitlint -e .git/COMMIT_EDITMSG --verbose
# --help로 모든 옵션 확인
npx commitlint --help