Files
gh-wasabeef-claude-code-coo…/commands/semantic-commit.md
2025-11-30 09:05:40 +08:00

1138 lines
29 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Semantic Commit
큰 변경사항을 의미 있는 최소 단위로 분할하여, 시맨틱한 커밋 메시지와 함께 순차적으로 커밋합니다. 외부 도구에 의존하지 않고 git 표준 명령어만 사용합니다.
### 사용법
```bash
/semantic-commit [옵션]
```
### 옵션
- `--dry-run` : 실제 커밋은 하지 않고, 제안되는 커밋 분할만 표시
- `--lang <언어>` : 커밋 메시지 언어를 강제 지정(en, ko)
- `--max-commits <수>` : 최대 커밋 수 지정(기본값: 10)
### 기본 예시
```bash
# 현재 변경사항을 분석해서 논리적 단위로 커밋
/semantic-commit
# 분할안만 확인 (실제 커밋 없음)
/semantic-commit --dry-run
# 영어로 커밋 메시지 생성
/semantic-commit --lang en
# 한국어로 커밋 메시지 생성
/semantic-commit --lang ko
# 최대 5 개 커밋으로 분할
/semantic-commit --max-commits 5
```
### 동작 플로
1. **변경 분석**: `git diff HEAD`로 전체 변경사항 취득
2. **파일 분류**: 변경된 파일을 논리적으로 그룹화
3. **커밋 제안**: 각 그룹에 대해 시맨틱한 커밋 메시지 생성
4. **순차 실행**: 사용자 확인 후 각 그룹을 순차적으로 커밋
### 변경 분할의 핵심 기능
#### "큰 변경사항" 탐지
다음 조건으로 큰 변경사항으로 탐지:
1. **변경 파일 수**: 5 개 이상의 파일 변경
2. **변경 라인 수**: 100 라인 이상의 변경
3. **복수 기능**: 2 개 이상의 기능 영역에 걸친 변경
4. **혼재 패턴**: feat + fix + docs 가 혼재
```bash
# 변경 규모 분석
CHANGED_FILES=$(git diff HEAD --name-only | wc -l)
CHANGED_LINES=$(git diff HEAD --stat | tail -1 | grep -o '[0-9]\+ insertions\|[0-9]\+ deletions' | awk '{sum+=$1} END {print sum}')
if [ $CHANGED_FILES -ge 5 ] || [ $CHANGED_LINES -ge 100 ]; then
echo "큰 변경사항 탐지: 분할을 권장"
fi
```
#### "의미 있는 최소 단위"로의 분할 전략
##### 1. 기능 경계를 통한 분할
```bash
# 디렉터리 구조에서 기능 단위 특정
git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq
# → src/auth, src/api, components/ui 등
```
##### 2. 변경 종별을 통한 분리
```bash
# 신규 파일 vs 기존 파일 수정
git diff HEAD --name-status | grep '^A' # 신규 파일
git diff HEAD --name-status | grep '^M' # 수정 파일
git diff HEAD --name-status | grep '^D' # 삭제 파일
```
##### 3. 의존 관계 분석
```bash
# 임포트 관계 변경 탐지
git diff HEAD | grep -E '^[+-].*import|^[+-].*require' | \
cut -d' ' -f2- | sort | uniq
```
#### 파일 단위의 상세 분석
```bash
# 변경된 파일 목록 취득
git diff HEAD --name-only
# 각 파일의 변경 내용을 개별 분석
git diff HEAD -- <file>
# 파일의 변경 타입 판정
git diff HEAD --name-status | while read status file; do
case $status in
A) echo "$file: 신규 생성" ;;
M) echo "$file: 수정" ;;
D) echo "$file: 삭제" ;;
R*) echo "$file: 이름 변경" ;;
esac
done
```
#### 논리적 그룹화 기준
1. **기능 단위**: 동일 기능 관련 파일
- `src/auth/` 하위 파일 → 인증 기능
- `components/` 하위 파일 → UI 컴포넌트
2. **변경 종별**: 같은 종류의 변경
- 테스트 파일만 → `test:`
- 문서만 → `docs:`
- 설정 파일만 → `chore:`
3. **의존 관계**: 상호 관련 파일
- 모델 + 마이그레이션
- 컴포넌트 + 스타일
4. **변경 규모**: 적절한 커밋 크기 유지
- 1 커밋당 10 파일 이하
- 관련성 높은 파일 그룹화
### 출력 예시
```bash
$ /semantic-commit
변경 분석 중...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
탐지된 변경사항:
• src/auth/login.ts (수정)
• src/auth/register.ts (신규)
• src/auth/types.ts (수정)
• tests/auth.test.ts (신규)
• docs/authentication.md (신규)
제안되는 커밋 분할:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
커밋 1/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
메시지: feat: implement user registration and login system
포함되는 파일:
• src/auth/login.ts
• src/auth/register.ts
• src/auth/types.ts
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
커밋 2/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
메시지: test: add comprehensive tests for authentication system
포함되는 파일:
• tests/auth.test.ts
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
커밋 3/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
메시지: docs: add authentication system documentation
포함되는 파일:
• docs/authentication.md
이 분할안으로 커밋을 실행하시겠습니까? (y/n/edit):
```
### 실행 시 선택지
- `y` : 제안된 커밋 분할로 실행
- `n` : 취소
- `edit` : 커밋 메시지를 개별 편집
- `merge <번호 1> <번호 2>` : 지정한 커밋을 합치기
- `split <번호>` : 지정한 커밋을 더 분할
### Dry Run 모드
```bash
$ /semantic-commit --dry-run
변경 분석 중... (DRY RUN)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[커밋 분할 제안 표시]
DRY RUN 모드: 실제 커밋은 실행되지 않습니다
💡 실행하려면 --dry-run 옵션을 제거하고 다시 실행하세요
```
### 스마트 분석 기능
#### 1. 프로젝트 구조 이해
- `package.json`, `Cargo.toml`, `pom.xml` 등에서 프로젝트 종류 판정
- 폴더 구조에서 기능 단위 추측
#### 2. 변경 패턴 인식
```bash
# 버그 수정 패턴 탐지
- "fix", "bug", "error" 등의 키워드
- 예외 처리 추가
- 조건 분기 수정
# 새 기능 패턴 탐지
- 새 파일 생성
- 새 메서드 추가
- API 엔드포인트 추가
```
#### 3. 의존 관계 분석
- import 문의 변경
- 타입 정의 추가/수정
- 설정 파일과의 연관성
### 기술적 구현
#### Git 표준 명령어를 통한 순차 커밋 구현
##### 1. 전처리: 현재 상태 저장
```bash
# 스테이징되지 않은 변경사항이 있으면 일단 리셋
git reset HEAD
git status --porcelain > /tmp/original_state.txt
# 작업 브랜치 확인
CURRENT_BRANCH=$(git branch --show-current)
echo "작업 중인 브랜치: $CURRENT_BRANCH"
```
##### 2. 그룹별 순차 커밋 실행
```bash
# 분할 계획 읽기
while IFS= read -r commit_plan; do
group_num=$(echo "$commit_plan" | cut -d':' -f1)
files=$(echo "$commit_plan" | cut -d':' -f2- | tr ' ' '\n')
echo "=== 커밋 $group_num 실행 ==="
# 해당 파일만 스테이징
echo "$files" | while read file; do
if [ -f "$file" ]; then
git add "$file"
echo "스테이징: $file"
fi
done
# 스테이징 상태 확인
staged_files=$(git diff --staged --name-only)
if [ -z "$staged_files" ]; then
echo "경고: 스테이징된 파일이 없습니다"
continue
fi
# 커밋 메시지 생성 (LLM 분석)
commit_msg=$(generate_commit_message_for_staged_files)
# 사용자 확인
echo "제안 커밋 메시지: $commit_msg"
echo "스테이징된 파일:"
echo "$staged_files"
read -p "이 커밋을 실행하시겠습니까? (y/n): " confirm
if [ "$confirm" = "y" ]; then
# 커밋 실행
git commit -m "$commit_msg"
echo "✅ 커밋 $group_num 완료"
else
# 스테이징 취소
git reset HEAD
echo "❌ 커밋 $group_num 건너뛰기"
fi
done < /tmp/commit_plan.txt
```
##### 3. 에러 처리와 롤백
```bash
# 프리커밋 훅 실패 시 처리
commit_with_retry() {
local commit_msg="$1"
local max_retries=2
local retry_count=0
while [ $retry_count -lt $max_retries ]; do
if git commit -m "$commit_msg"; then
echo "✅ 커밋 성공"
return 0
else
echo "❌ 커밋 실패 (시도 $((retry_count + 1))/$max_retries)"
# 프리커밋 훅의 자동 수정 적용
if git diff --staged --quiet; then
echo "프리커밋 훅이 변경사항을 자동 수정했습니다"
git add -u
fi
retry_count=$((retry_count + 1))
fi
done
echo "❌ 커밋에 실패했습니다. 수동으로 확인하세요."
return 1
}
# 중단에서 복구
resume_from_failure() {
echo "중단된 커밋 처리를 감지했습니다"
echo "현재 스테이징 상태:"
git status --porcelain
read -p "처리를 계속하시겠습니까? (y/n): " resume
if [ "$resume" = "y" ]; then
# 마지막 커밋 위치에서 재개
last_commit=$(git log --oneline -1 --pretty=format:"%s")
echo "마지막 커밋: $last_commit"
else
# 완전 리셋
git reset HEAD
echo "처리를 리셋했습니다"
fi
}
```
##### 4. 완료 후 검증
```bash
# 모든 변경사항이 커밋되었는지 확인
remaining_changes=$(git status --porcelain | wc -l)
if [ $remaining_changes -eq 0 ]; then
echo "✅ 모든 변경사항이 커밋되었습니다"
else
echo "⚠️ 커밋되지 않은 변경사항이 남아있습니다:"
git status --short
fi
# 커밋 이력 표시
echo "생성된 커밋:"
git log --oneline -n 10 --graph
```
##### 5. 자동 푸시 억제
```bash
# 주의: 자동 푸시는 하지 않음
echo "📝 주의: 자동 푸시는 실행되지 않습니다"
echo "필요시 다음 명령어로 푸시하세요:"
echo " git push origin $CURRENT_BRANCH"
```
#### 분할 알고리즘 상세
##### 단계 1: 초기 분석
```bash
# 모든 변경 파일 취득 및 분류
git diff HEAD --name-status | while read status file; do
echo "$status:$file"
done > /tmp/changes.txt
# 기능 디렉터리별 변경 통계
git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq -c
```
##### 단계 2: 기능 경계를 통한 초기 그룹화
```bash
# 디렉터리 기반 그룹화
GROUPS=$(git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq)
for group in $GROUPS; do
echo "=== 그룹: $group ==="
git diff HEAD --name-only | grep "^$group" | head -10
done
```
##### 단계 3: 변경 내용의 유사성 분석
```bash
# 각 파일의 변경 타입 분석
git diff HEAD --name-only | while read file; do
# 새 함수/클래스 추가 탐지
NEW_FUNCTIONS=$(git diff HEAD -- "$file" | grep -c '^+.*function\|^+.*class\|^+.*def ')
# 버그 수정 패턴 탐지
BUG_FIXES=$(git diff HEAD -- "$file" | grep -c '^+.*fix\|^+.*bug\|^-.*error')
# 테스트 파일 판정
if [[ "$file" =~ test|spec ]]; then
echo "$file: TEST"
elif [ $NEW_FUNCTIONS -gt 0 ]; then
echo "$file: FEAT"
elif [ $BUG_FIXES -gt 0 ]; then
echo "$file: FIX"
else
echo "$file: REFACTOR"
fi
done
```
##### 단계 4: 의존 관계를 통한 조정
```bash
# import 관계 분석
git diff HEAD | grep -E '^[+-].*import|^[+-].*from.*import' | \
while read line; do
echo "$line" | sed 's/^[+-]//' | awk '{print $2}'
done | sort | uniq > /tmp/imports.txt
# 관련 파일 그룹화
git diff HEAD --name-only | while read file; do
basename=$(basename "$file" .js .ts .py)
related=$(git diff HEAD --name-only | grep "$basename" | grep -v "^$file$")
if [ -n "$related" ]; then
echo "관련 파일 그룹: $file <-> $related"
fi
done
```
##### 단계 5: 커밋 크기 최적화
```bash
# 그룹 크기 조정
MAX_FILES_PER_COMMIT=8
current_group=1
file_count=0
git diff HEAD --name-only | while read file; do
if [ $file_count -ge $MAX_FILES_PER_COMMIT ]; then
current_group=$((current_group + 1))
file_count=0
fi
echo "커밋 $current_group: $file"
file_count=$((file_count + 1))
done
```
##### 단계 6: 최종 그룹 결정
```bash
# 분할 결과 검증
for group in $(seq 1 $current_group); do
files=$(grep "커밋 $group:" /tmp/commit_plan.txt | cut -d':' -f2-)
lines=$(echo "$files" | xargs git diff HEAD -- | wc -l)
echo "커밋 $group: $(echo "$files" | wc -w) 파일, $lines 라인 변경"
done
```
### Conventional Commits 준수
#### 기본 형식
```text
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
#### 표준 타입
**필수 타입**:
- `feat`: 새 기능 (사용자에게 보이는 기능 추가)
- `fix`: 버그 수정
**선택적 타입**:
- `build`: 빌드 시스템이나 외부 의존관계 변경
- `chore`: 기타 변경사항 (릴리즈에 영향하지 않음)
- `ci`: CI 설정 파일이나 스크립트 변경
- `docs`: 문서만의 변경
- `style`: 코드 의미에 영향하지 않는 변경 (공백, 포맷, 세미콜론 등)
- `refactor`: 버그 수정이나 기능 추가를 동반하지 않는 코드 변경
- `perf`: 성능 개선
- `test`: 테스트 추가나 수정
#### 스코프 (선택적)
변경의 영향 범위 표시:
```text
feat(api): add user authentication endpoint
fix(ui): resolve button alignment issue
docs(readme): update installation instructions
```
#### Breaking Change
API 의 파괴적 변경이 있는 경우:
```text
feat!: change user API response format
BREAKING CHANGE: user response now includes additional metadata
```
또는
```text
feat(api)!: change authentication flow
```
#### 프로젝트 규약의 자동 감지
**중요**: 프로젝트 고유 규약이 존재하면 그것을 우선합니다.
##### 1. CommitLint 설정 확인
다음 파일에서 설정을 자동 감지:
- `commitlint.config.js`
- `commitlint.config.mjs`
- `commitlint.config.cjs`
- `commitlint.config.ts`
- `.commitlintrc.js`
- `.commitlintrc.json`
- `.commitlintrc.yml`
- `.commitlintrc.yaml`
- `package.json``commitlint` 섹션
```bash
# 설정 파일 예시 확인
cat commitlint.config.mjs
cat .commitlintrc.json
grep -A 10 '"commitlint"' package.json
```
##### 2. 커스텀 타입 감지
프로젝트 고유 타입 예시:
```javascript
// commitlint.config.mjs
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"chore",
"wip", // 작업 중
"hotfix", // 긴급 수정
"release", // 릴리즈
"deps", // 의존성 업데이트
"config", // 설정 변경
],
],
},
};
```
##### 3. 언어 설정 감지
```javascript
// 프로젝트가 한국어 메시지를 사용하는 경우
export default {
rules: {
"subject-case": [0], // 한국어 대응을 위해 비활성화
"subject-max-length": [2, "always", 72], // 한국어는 문자 수 제한 조정
},
};
```
#### 자동 분석 흐름
1. **설정 파일 검색**
```bash
find . -name "commitlint.config.*" -o -name ".commitlintrc.*" | head -1
```
2. **기존 커밋 분석**
```bash
git log --oneline -50 --pretty=format:"%s"
```
3. **사용 타입 통계**
```bash
git log --oneline -100 --pretty=format:"%s" | \
grep -oE '^[a-z]+(\([^)]+\))?' | \
sort | uniq -c | sort -nr
```
#### 프로젝트 규약 예시
##### Angular 스타일
```text
feat(scope): add new feature
fix(scope): fix bug
docs(scope): update documentation
```
##### Gitmoji 병용 스타일
```text
✨ feat: add user registration
🐛 fix: resolve login issue
📚 docs: update API docs
```
##### 한국어 프로젝트
```text
feat: 사용자 등록 기능 추가
fix: 로그인 처리 버그 수정
docs: API 문서 업데이트
```
### 언어 판정
이 명령어에서 완결되는 언어 판정 로직:
1. **CommitLint 설정**에서 언어 설정 확인
```bash
# subject-case 규칙이 비활성화되면 한국어로 판정
grep -E '"subject-case".*\[0\]|subject-case.*0' commitlint.config.*
```
2. **git log 분석**을 통한 자동 판정
```bash
# 최근 20 개 커밋의 언어 분석
git log --oneline -20 --pretty=format:"%s" | \
grep -E '^[가-힣]' | wc -l
# 50% 이상이 한국어면 한국어 모드
```
3. **프로젝트 파일**의 언어 설정
```bash
# README.md 언어 확인
head -10 README.md | grep -E '[가-힣]' | wc -l
# package.json 의 description 확인
grep -E '"description".*[가-힣]' package.json
```
4. **변경 파일 내** 주석·문자열 분석
```bash
# 변경된 파일의 주석 언어 확인
git diff HEAD | grep -E '^[+-].*//.*[가-힣]' | wc -l
```
#### 판정 알고리즘
```bash
# 언어 판정 점수 계산
KOREAN_SCORE=0
# 1. CommitLint 설정 (+3 점)
if grep -q '"subject-case".*\[0\]' commitlint.config.* 2>/dev/null; then
KOREAN_SCORE=$((KOREAN_SCORE + 3))
fi
# 2. git log 분석 (최대 +2 점)
KOREAN_COMMITS=$(git log --oneline -20 --pretty=format:"%s" | \
grep -cE '[가-힣]' 2>/dev/null || echo 0)
if [ $KOREAN_COMMITS -gt 10 ]; then
KOREAN_SCORE=$((KOREAN_SCORE + 2))
elif [ $KOREAN_COMMITS -gt 5 ]; then
KOREAN_SCORE=$((KOREAN_SCORE + 1))
fi
# 3. README.md 확인 (+1 점)
if head -5 README.md 2>/dev/null | grep -qE '[가-힣]'; then
KOREAN_SCORE=$((KOREAN_SCORE + 1))
fi
# 4. 변경 파일 내용 확인 (+1 점)
if git diff HEAD 2>/dev/null | grep -qE '^[+-].*[가-힣]'; then
KOREAN_SCORE=$((KOREAN_SCORE + 1))
fi
# 판정: 3 점 이상이면 한국어 모드
if [ $KOREAN_SCORE -ge 3 ]; then
LANGUAGE="ko"
else
LANGUAGE="en"
fi
```
### 설정 파일 자동 읽기
#### 실행 시 동작
명령어 실행 시 다음 순서로 설정 확인:
1. **CommitLint 설정 파일 검색**
```bash
# 다음 순서로 검색하여 처음 찾은 파일 사용
commitlint.config.mjs
commitlint.config.js
commitlint.config.cjs
commitlint.config.ts
.commitlintrc.js
.commitlintrc.json
.commitlintrc.yml
.commitlintrc.yaml
package.json (commitlint 섹션)
```
2. **설정 내용 분석**
- 사용 가능한 타입 목록 추출
- 스코프 제한 확인
- 메시지 길이 제한 취득
- 언어 설정 확인
3. **기존 커밋 이력 분석**
```bash
# 최근 커밋에서 사용 패턴 학습
git log --oneline -100 --pretty=format:"%s" | \
head -20
```
#### 설정 예시 분석
**표준 commitlint.config.mjs**:
```javascript
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
["feat", "fix", "docs", "style", "refactor", "perf", "test", "chore"],
],
"scope-enum": [2, "always", ["api", "ui", "core", "auth", "db"]],
},
};
```
**한국어 대응 설정**:
```javascript
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"subject-case": [0], // 한국어를 위해 비활성화
"subject-max-length": [2, "always", 72],
"type-enum": [
2,
"always",
["feat", "fix", "docs", "style", "refactor", "test", "chore"],
],
},
};
```
**커스텀 타입 포함 설정**:
```javascript
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"chore",
"wip", // Work in Progress
"hotfix", // 긴급 수정
"release", // 릴리즈 준비
"deps", // 의존성 업데이트
"config", // 설정 변경
],
],
},
};
```
#### 폴백 동작
설정 파일을 찾을 수 없는 경우:
1. **git log 분석**을 통한 자동 추측
```bash
# 최근 100 개 커밋에서 타입 추출
git log --oneline -100 --pretty=format:"%s" | \
grep -oE '^[a-z]+(\([^)]+\))?' | \
sort | uniq -c | sort -nr
```
2. **Conventional Commits 표준**을 기본 사용
```
feat, fix, docs, style, refactor, perf, test, chore, build, ci
```
3. **언어 판정**
- 한국어 커밋이 50% 이상 → 한국어 모드
- 그 외 → 영어 모드
### 전제 조건
- Git 저장소 내에서 실행
- 커밋되지 않은 변경사항이 존재할 것
- 스테이징된 변경사항은 일시적으로 리셋됩니다
### 주의사항
- **자동 푸시 없음**: 커밋 후 `git push`는 수동 실행
- **브랜치 생성 없음**: 현재 브랜치에서 커밋
- **백업 권장**: 중요한 변경 전에는 `git stash`로 백업
### 프로젝트 규약의 우선순위
커밋 메시지 생성 시 우선순위:
1. **CommitLint 설정** (최우선)
- `commitlint.config.*` 파일 설정
- 커스텀 타입이나 스코프 제한
- 메시지 길이나 케이스 제한
2. **기존 커밋 이력** (2 순위)
- 실제 사용된 타입 통계
- 메시지 언어(한국어/영어)
- 스코프 사용 패턴
3. **프로젝트 종류** (3 순위)
- `package.json` → Node.js 프로젝트
- `Cargo.toml` → Rust 프로젝트
- `pom.xml` → Java 프로젝트
4. **Conventional Commits 표준** (폴백)
- 설정을 찾을 수 없는 경우의 표준 동작
#### 규약 감지 실례
**Monorepo 에서 scope 자동 감지**:
```bash
# packages/ 폴더에서 scope 추측
ls packages/ | head -10
# → api, ui, core, auth 등을 scope 로 제안
```
**프레임워크별 규약**:
```javascript
// Angular 프로젝트
{
'scope-enum': [2, 'always', [
'animations', 'common', 'core', 'forms', 'http', 'platform-browser',
'platform-server', 'router', 'service-worker', 'upgrade'
]]
}
// React 프로젝트
{
'scope-enum': [2, 'always', [
'components', 'hooks', 'utils', 'types', 'styles', 'api'
]]
}
```
**기업·팀 고유 규약**:
```javascript
// 한국 기업에서 자주 보이는 패턴
{
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore',
'wip', // 작업 중(풀 리퀘스트용)
'hotfix', // 긴급 수정
'release' // 릴리즈 준비
]],
'subject-case': [0], // 한국어 대응
'subject-max-length': [2, 'always', 72] // 한국어는 길게 설정
}
```
### 베스트 프랙티스
1. **프로젝트 규약 준수**: 기존 설정이나 패턴을 따름
2. **작은 변경 단위**: 1 개 커밋은 1 개의 논리적 변경
3. **명확한 메시지**: 무엇을 변경했는지가 명확
4. **관련성 중시**: 기능적으로 관련된 파일을 그룹화
5. **테스트 분리**: 테스트 파일은 별도 커밋으로
6. **설정 파일 활용**: CommitLint 를 도입해 팀 전체 규약 통일
### 실제 분할 예시(Before/After)
#### 예시 1: 대규모 인증 시스템 추가
**Before(하나의 거대한 커밋):**
```bash
# 변경된 파일(15 개 파일, 850 라인 변경)
src/auth/login.js # 신규 생성
src/auth/register.js # 신규 생성
src/auth/password.js # 신규 생성
src/auth/types.js # 신규 생성
src/api/auth-routes.js # 신규 생성
src/middleware/auth.js # 신규 생성
src/database/migrations/001_users.sql # 신규 생성
src/database/models/user.js # 신규 생성
tests/auth/login.test.js # 신규 생성
tests/auth/register.test.js # 신규 생성
tests/api/auth-routes.test.js # 신규 생성
docs/authentication.md # 신규 생성
package.json # 의존성 추가
README.md # 사용법 추가
.env.example # 환경변수 예시 추가
# 기존의 문제 있는 커밋
feat: implement complete user authentication system with login, registration, password reset, API routes, database models, tests and documentation
```
**After(의미 있는 5 개 커밋으로 분할):**
```bash
# 커밋 1: 데이터베이스 기반
feat(db): add user model and authentication schema
포함 파일:
- src/database/migrations/001_users.sql
- src/database/models/user.js
- src/auth/types.js
이유: 데이터베이스 구조는 다른 기능의 기반이므로 먼저 커밋
# 커밋 2: 인증 로직
feat(auth): implement core authentication functionality
포함 파일:
- src/auth/login.js
- src/auth/register.js
- src/auth/password.js
- src/middleware/auth.js
이유: 인증의 핵심 비즈니스 로직을 한 번에 커밋
# 커밋 3: API 엔드포인트
feat(api): add authentication API routes
포함 파일:
- src/api/auth-routes.js
이유: API 레이어는 인증 로직에 의존하므로 뒤에 커밋
# 커밋 4: 포괄적 테스트
test(auth): add comprehensive authentication tests
포함 파일:
- tests/auth/login.test.js
- tests/auth/register.test.js
- tests/api/auth-routes.test.js
이유: 구현 완료 후 테스트를 일괄 추가
# 커밋 5: 설정과 문서
docs(auth): add authentication documentation and configuration
포함 파일:
- docs/authentication.md
- package.json
- README.md
- .env.example
이유: 문서와 설정은 마지막에 함께 커밋
```
#### 예시 2: 버그 수정과 리팩터링 혼재
**Before(혼재된 문제 있는 커밋):**
```bash
# 변경된 파일(8 개 파일, 320 라인 변경)
src/user/service.js # 버그 수정 + 리팩터링
src/user/validator.js # 신규 생성(리팩터링)
src/auth/middleware.js # 버그 수정
src/api/user-routes.js # 버그 수정 + 에러 처리 개선
tests/user.test.js # 테스트 추가
tests/auth.test.js # 버그 수정 테스트 추가
docs/user-api.md # 문서 업데이트
package.json # 의존성 업데이트
# 문제 있는 커밋
fix: resolve user validation bugs and refactor validation logic with improved error handling
```
**After(종류별로 3 개 커밋으로 분할):**
```bash
# 커밋 1: 긴급 버그 수정
fix: resolve user validation and authentication bugs
포함 파일:
- src/user/service.js(버그 수정 부분만)
- src/auth/middleware.js
- tests/auth.test.js(버그 수정 테스트만)
이유: 프로덕션 환경에 영향을 주는 버그는 최우선 수정
# 커밋 2: 검증 로직 리팩터링
refactor: extract and improve user validation logic
포함 파일:
- src/user/service.js(리팩터링 부분)
- src/user/validator.js
- src/api/user-routes.js
- tests/user.test.js
이유: 구조 개선은 기능 단위로 함께 커밋
# 커밋 3: 문서와 의존성 업데이트
chore: update documentation and dependencies
포함 파일:
- docs/user-api.md
- package.json
이유: 개발 환경 정비는 마지막에 함께 커밋
```
#### 예시 3: 여러 기능 동시 개발
**Before(기능 횡단 거대 커밋):**
```bash
# 변경된 파일(12 개 파일, 600 라인 변경)
src/user/profile.js # 새 기능 A
src/user/avatar.js # 새 기능 A
src/notification/email.js # 새 기능 B
src/notification/sms.js # 새 기능 B
src/api/profile-routes.js # 새 기능 A 용 API
src/api/notification-routes.js # 새 기능 B 용 API
src/dashboard/widgets.js # 새 기능 C
src/dashboard/charts.js # 새 기능 C
tests/profile.test.js # 새 기능 A 용 테스트
tests/notification.test.js # 새 기능 B 용 테스트
tests/dashboard.test.js # 새 기능 C 용 테스트
package.json # 전체 기능 의존성
# 문제 있는 커밋
feat: add user profile management, notification system and dashboard widgets
```
**After(기능별로 4 개 커밋으로 분할):**
```bash
# 커밋 1: 사용자 프로필 기능
feat(profile): add user profile management
포함 파일:
- src/user/profile.js
- src/user/avatar.js
- src/api/profile-routes.js
- tests/profile.test.js
이유: 프로필 기능은 독립된 기능 단위
# 커밋 2: 알림 시스템
feat(notification): implement email and SMS notifications
포함 파일:
- src/notification/email.js
- src/notification/sms.js
- src/api/notification-routes.js
- tests/notification.test.js
이유: 알림 기능은 독립된 기능 단위
# 커밋 3: 대시보드 위젯
feat(dashboard): add interactive widgets and charts
포함 파일:
- src/dashboard/widgets.js
- src/dashboard/charts.js
- tests/dashboard.test.js
이유: 대시보드 기능은 독립된 기능 단위
# 커밋 4: 의존성과 인프라 업데이트
chore: update dependencies for new features
포함 파일:
- package.json
이유: 공통 의존성 업데이트는 마지막에 함께
```
### 분할 효과 비교
| 항목 | Before(거대 커밋) | After(적절한 분할) |
| ------------- | ------------------------ | ------------------------------ |
| **리뷰성** | ❌ 매우 어려움 | ✅ 각 커밋이 작아 리뷰 가능 |
| **버그 추적** | ❌ 문제 위치 파악 어려움 | ✅ 문제 있는 커밋 즉시 파악 |
| **되돌리기** | ❌ 전체를 되돌려야 함 | ✅ 문제 부분만 선택적 되돌리기 |
| **병렬 개발** | ❌ 충돌 발생 쉬움 | ✅ 기능별로 병합 용이 |
| **배포** | ❌ 전체 기능 일괄 배포 | ✅ 단계적 배포 가능 |
### 트러블슈팅
#### 커밋 실패 시
- 프리커밋 훅 확인
- 의존성 해결
- 개별 파일로 재시도
#### 분할이 적절하지 않은 경우
- `--max-commits` 옵션으로 조정
- 수동 `edit` 모드 사용
- 더 세밀한 단위로 재실행