AI 기반 git 커밋 메시지 자동 생성 CLI 도구.
스테이징된 변경사항을 분석하여 Conventional Commit 메시지를 Claude 또는 OpenAI로 생성합니다. Gitmoji, 다국어, 대화형 선택을 지원합니다.
아카이브됨 — 더 이상 유지보수하지 않습니다. 작업 기록과 아래 판단을 남기기 위해 공개 상태로 둡니다.
2026년 3월에 직접 쓰려고 만들었고, 한동안 실제로 썼습니다. 지금도 동작합니다 — 테스트가 있고 CI가 Linux/Windows에서 Node 20·22·24로 돌아갑니다.
지금은 쓰지 않는데, 그 이유가 기록해둘 만합니다.
제 작업 방식이 에이전트 중심으로 옮겨갔습니다. 에이전트가 코드를 짜면 커밋 메시지도 같이 쓰는데, 그게 이 도구보다 낫습니다. 모델이 더 좋아서가 아니라 가진 정보가 다르기 때문입니다.
aicommit은 diff를 읽고 의도를 추측합니다. 코드를 짠 에이전트는 의도를 이미 알고 있습니다.
커밋 메시지의 가치는 대부분 왜에 있는데, 그 왜는 diff에 남지 않습니다. feat: / fix: / refactor: 구분조차 변경분만으로는 복원되지 않을 때가 많습니다 — 같은 수정이 무엇을 하려던 것이었느냐에 따라 셋 다 될 수 있으니까요. 작업의 하류에 선 도구는, 상류의 작성자가 애초에 추측할 필요조차 없던 것을 추측하고 있는 셈입니다.
이건 품질 격차가 아니라 구조적 열세라서, 프롬프트를 아무리 다듬어도 좁혀지지 않습니다. 이 분야가 계속 작았던 이유이기도 합니다 — 가장 많이 쓰이는 도구가 주간 6천 다운로드 수준인데, 그게 얹히는 git 훅 인프라(husky, lint-staged)는 수천만입니다.
그래도 맞는 자리: 손으로 직접 짠 코드, 코딩 에이전트를 쓸 수 없거나 쓰지 않는 환경, 그리고 지난 커밋 메시지를 정리할 때.
버틴 것과 못 버틴 것: 프로바이더 추상화(프로바이더 추가)는 호출 계층에서는 제 역할을 했습니다 — 새 프로바이더는 독립된 파일 하나와 레지스트리 한 줄이면 됩니다. 다만 설정 계층에서 멈춥니다. 설정 마법사가 프로바이더 이름과 키 필드를 하드코딩하고 있어서, 세 번째 프로바이더를 붙이려면 그쪽도 고쳐야 합니다. 이 두 관심사를 분리하는 게 다시 한다면 바꿀 부분입니다. 파싱 fallback 체인과 설정 우선순위 규칙은 다른 프로젝트에 그대로 가져갈 만합니다.
소스에서 설치합니다 — npm에 발행되어 있지 않습니다.
# 1. 소스에서 설치
git clone https://github.com/solzip/ai-commit.git
cd ai-commit && npm install && npm link그다음 본인의 git 프로젝트에서:
# 2. 변경사항 스테이징
git add .
# 3. AI가 커밋 메시지 생성
aicommit처음 실행하면 API 키 설정을 자동으로 안내합니다.
$ aicommit
Staged files:
src/auth/login.js
src/auth/token.js
✔ Analysis complete
📝 Suggested commit messages:
1. feat(auth): JWT 토큰 갱신 엔드포인트 추가
2. feat: Redis 캐시를 활용한 토큰 갱신 로직 구현
3. feat(auth): 7일 만료 자동 JWT 갱신 추가
? Select a message: (Use arrow keys)
❯ 1. feat(auth): JWT 토큰 갱신 엔드포인트 추가
2. feat: Redis 캐시를 활용한 토큰 갱신 로직 구현
3. feat(auth): 7일 만료 자동 JWT 갱신 추가
──────────────
✏️ Edit message
🔄 Regenerate
❌ Cancel
✅ Committed: feat(auth): JWT 토큰 갱신 엔드포인트 추가
Undo: git reset --soft HEAD~1 | Amend: git commit --amend
--gitmoji 사용 시:
📝 Suggested commit messages:
1. ✨ feat(auth): JWT 토큰 갱신 엔드포인트 추가
2. 🐛 fix(api): 토큰 갱신 타임아웃 문제 해결
3. ♻️ refactor: 인증 미들웨어 체인 단순화
- 멀티 프로바이더 — Claude와 OpenAI를
--provider나 config로 자유롭게 전환 - Conventional Commits — 표준 포맷 (
feat,fix,refactor, ...) 기본 활성화 - Gitmoji — 이모지 접두사 지원 (
--gitmoji) ✨ 🐛 ♻️ 등 - 다국어 — 영어/한국어 커밋 메시지 (
--lang ko) - 대화형 — 메시지 선택, 수정, 재생성을 반복 가능
- 설정 없이 시작 — 처음 실행 시 API 키 설정을 자동 안내
- Staged 파일 미리보기 — AI 분석 전 어떤 파일이 커밋되는지 확인
- 모델 설정 가능 — 코드 수정 없이 AI 모델 변경
- 요청 타임아웃 — 30초 fetch 타임아웃으로 느린 네트워크 대응
- 안전한 커밋 UX — 커밋 후 undo/amend 명령어 안내
npm에 발행되어 있지 않습니다 — 소스에서 설치합니다:
git clone https://github.com/solzip/ai-commit.git
cd ai-commit
npm install
npm link # `aicommit` 명령을 전역에서 사용 가능하게 함제거할 때: npm unlink -g aicommit
요구사항: Node.js >= 20
git clone https://github.com/solzip/ai-commit.git
cd ai-commit
npm install
node bin/ai-commit.js --helpaicommit # 커밋 메시지 생성 (기본 프로바이더)
aicommit --provider openai # OpenAI 사용
aicommit --lang ko # 한국어 커밋 메시지
aicommit --gitmoji # Gitmoji 접두사 추가 (✨ 🐛 ♻️)
aicommit config # 대화형 설정 (API 키, 기본 설정)| 옵션 | 설명 | 기본값 |
|---|---|---|
--provider <name> |
AI 프로바이더 (claude 또는 openai) |
claude |
--lang <code> |
커밋 메시지 언어 (en 또는 ko) |
en |
--gitmoji |
Gitmoji 이모지 접두사 추가 | 설정 파일 값 |
--no-gitmoji |
설정에서 켜져 있어도 gitmoji 비활성화 | 설정 파일 값 |
-y, --yes |
첫 제안을 프롬프트 없이 바로 커밋 | false |
-V, --version |
버전 표시 | — |
-h, --help |
도움말 표시 | — |
--gitmoji와 --no-gitmoji는 둘 다 설정 파일을 덮어씁니다. 생략하면 설정 파일 값을 따릅니다.
stdin이나 stdout이 TTY가 아니면 --yes가 자동 적용됩니다. 덕분에 스크립트나 git 훅에서 답할 수 없는 프롬프트에 걸려 죽지 않습니다.
conventionalCommit과 gitmoji 설정 조합에 따라 4가지 포맷을 지원합니다:
| conventionalCommit | gitmoji | 포맷 | 예시 |
|---|---|---|---|
| true | false | <type>(<scope>): <description> |
feat(auth): 로그인 엔드포인트 추가 |
| true | true | <emoji> <type>(<scope>): <description> |
✨ feat(auth): 로그인 엔드포인트 추가 |
| false | true | <emoji> <description> |
✨ 로그인 엔드포인트 추가 |
| false | false | 자유 형식 | 로그인 엔드포인트 추가 |
| 이모지 | 타입 | 의미 |
|---|---|---|
| ✨ | feat | 새 기능 |
| 🐛 | fix | 버그 수정 |
| ♻️ | refactor | 리팩토링 |
| 📝 | docs | 문서 |
| 💄 | style | UI/스타일 |
| ✅ | test | 테스트 |
| 🔧 | chore | 설정/도구 |
| ⚡ | perf | 성능 개선 |
| 👷 | ci | CI/CD |
| 📦 | build | 빌드 시스템 |
| 🔥 | remove | 코드/파일 삭제 |
| 🚀 | deploy | 배포 |
| 🔒 | security | 보안 수정 |
| ⬆️ | upgrade | 의존성 업그레이드 |
| 🎨 | format | 코드 포맷팅 |
aicommit config설정 항목:
- 기본 AI 프로바이더 (Claude / OpenAI)
- 선택한 프로바이더의 API 키 (Enter로 기존 키 유지 가능)
- 기본 언어 (English / 한국어)
- Conventional Commits 사용 여부
- Gitmoji 사용 여부
모든 설정은 ~/.ai-commit.json에 저장됩니다:
{
"provider": "claude",
"claudeApiKey": "sk-ant-...",
"openaiApiKey": "sk-...",
"language": "en",
"conventionalCommit": true,
"gitmoji": false,
"maxSuggestions": 3,
"claudeModel": "claude-sonnet-5",
"openaiModel": "gpt-4o-mini",
"timeout": 30000
}| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
provider |
string | "claude" |
기본 AI 프로바이더 |
claudeApiKey |
string | — | Claude API 키 |
openaiApiKey |
string | — | OpenAI API 키 |
language |
string | "en" |
커밋 메시지 언어 (en, ko) |
conventionalCommit |
boolean | true |
Conventional Commits 포맷 사용 |
gitmoji |
boolean | false |
Gitmoji 접두사 추가 |
maxSuggestions |
number | 3 |
생성할 제안 수 |
claudeModel |
string | "claude-sonnet-5" |
사용할 Claude 모델 |
openaiModel |
string | "gpt-4o-mini" |
사용할 OpenAI 모델 |
timeout |
number | 30000 |
API 요청 타임아웃 (밀리초) |
환경 변수로 API 키를 설정할 수 있습니다 (설정 파일보다 우선):
export AI_COMMIT_CLAUDE_KEY=sk-ant-...
export AI_COMMIT_OPENAI_KEY=sk-...CI/CD 환경이나 공유 머신에서 설정 파일 없이 사용할 때 유용합니다.
CLI 옵션 (--provider, --lang, --gitmoji)
↓ 우선
환경 변수 (AI_COMMIT_CLAUDE_KEY, AI_COMMIT_OPENAI_KEY)
↓ 우선
설정 파일 (~/.ai-commit.json)
↓ 우선
기본값
| 프로바이더 | 기본 모델 | 최대 Diff | API |
|---|---|---|---|
| Claude | claude-sonnet-5 | ~15,000자 | Anthropic Messages API |
| OpenAI | gpt-4o-mini | ~12,000자 | OpenAI Chat Completions |
모델은 ~/.ai-commit.json의 claudeModel, openaiModel로 코드 수정 없이 변경 가능합니다.
새 AI 프로바이더(예: Gemini) 추가는 3단계:
Step 1. src/providers/gemini.js 생성:
import { AIProvider } from './AIProvider.js';
import { parseAIResponse } from './parse.js';
export class GeminiProvider extends AIProvider {
constructor(apiKey, config = {}) {
super('gemini', apiKey, 12000);
this.model = config.geminiModel || 'gemini-pro';
this.timeout = config.timeout || 30000;
}
async generateCommitMessages(prompt, options) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch('https://generativelanguage.googleapis.com/...', {
// ... API 호출
signal: controller.signal,
});
// ... 응답 파싱
return parseAIResponse(text, options.maxSuggestions);
} finally {
clearTimeout(timer);
}
}
}Step 2. src/providers/registry.js에 등록:
import { GeminiProvider } from './gemini.js';
registerProvider('gemini', GeminiProvider);Step 3. src/core/config.js에 geminiApiKey 필드 추가
git diff --staged
→ Staged 파일 목록 표시
→ truncateDiff() (너무 크면)
→ buildPrompt(diff, {lang, format, gitmoji})
→ provider.generateCommitMessages(prompt)
→ parseAIResponse() (JSON → 줄바꿈 fallback → 재시도)
→ Inquirer (선택 / 수정 / 재생성 반복)
→ git commit -m "선택한 메시지"
→ undo/amend 힌트 표시
- 저장소 확인 — git repo인지 확인
- 설정 로드 + 옵션 검증 — 기본값 < 설정 파일 < 환경 변수 < CLI 옵션 순으로 머지한 뒤, 잘못된
--provider·--lang을 작업 시작 전에 거부 - staged 변경 읽기 — staged diff를 읽고 파일 목록 표시
- API 키 확인 — 없으면 config wizard 안내. 비대화형 터미널에서는 대신 방법을 알려주고 종료
- Diff 축소 — 프로바이더 제한 초과 시 stat summary + 부분 diff로 자동 축소
- 프롬프트 생성 — diff + 언어 + 포맷(conventional/gitmoji) + 제안 수 조합
- AI 호출 — 30초 타임아웃으로 전송. 파싱 실패 시 1회 자동 재시도
- 메시지 선택 — 선택·수정·재생성 반복.
--yes이거나 TTY가 아니면 첫 제안을 채택 - 커밋 — 셸을 거치지 않고 git을 직접 실행한 뒤 undo 명령어 안내
옵션 검증을 2단계에 둔 이유는, --provider gemini 같은 오타가 diff를 다 읽고 존재할 수 없는 키를 물어본 다음이 아니라 즉시 실패하도록 하기 위해서입니다.
| 에러 | 메시지 | 복구 |
|---|---|---|
| git repo 아님 | Not a git repository |
종료 |
| staged changes 없음 | No staged changes. Run 'git add' first |
종료 |
| API 키 없음 (대화형) | API key not configured for {provider} |
config wizard 자동 안내 |
| API 키 없음 (TTY 아님) | API key not configured + 환경 변수 설정 방법 |
종료 |
| 미지원 프로바이더 | Unknown provider: {name}. Available: claude, openai |
종료 |
| 미지원 언어 | Unknown language: {code}. Available: en, ko |
종료 |
| 마법사가 키 없이 종료 | Still no API key for {provider}. Aborting |
종료 (재귀 루프 방지) |
| 잘못된 API 키 (401) | Invalid API key for {provider} |
aicommit config 안내 |
| 요청 제한 (429) | Rate limited. Please try again later |
종료 |
| 서버 에러 (5xx) | {provider} API error ({status}) |
종료 |
| 네트워크/타임아웃 | Network error. Check your connection |
종료 (30초 타임아웃) |
| Diff 너무 큼 | Diff truncated (too large for AI context) |
stat summary로 자동 축소 |
| 파싱 실패 | — | 1회 자동 재시도 후 종료 |
- API 키는
~/.ai-commit.json에chmod 600(소유자만 읽기/쓰기)으로 저장 - 환경 변수 (
AI_COMMIT_CLAUDE_KEY,AI_COMMIT_OPENAI_KEY)가 설정 파일보다 우선하며, 설정 파일에 기록되지 않음 — 마법사가 파일 설정을 직접 읽으므로 환경 변수로만 준 키가 디스크에 남지 않습니다 - 커밋 시 셸 미경유 — 메시지를 git에 인자로 직접 전달하므로, 메시지 안의
$(...)나 백틱이 평가되지 않습니다 - 키 마스킹 — config wizard에서 기존 키를
sk-ant-***...***형태로 마스킹 표시 - 홈 디렉토리 저장 — 설정 파일은
~/에 위치, git 추적 대상 아님
.env나 키 파일을 git add 했다면 그 내용도 기기를 떠납니다. 검토하지 않은 변경에 이 도구를 쓰기 전에 git diff --staged를 확인하세요.
ai-commit/
├── bin/
│ └── ai-commit.js # CLI 엔트리포인트 + 인터랙션 (279줄)
├── src/
│ ├── core/
│ │ ├── config.js # 설정 로드/저장/wizard (151줄)
│ │ ├── git.js # Git 작업 (38줄)
│ │ └── prompt.js # 프롬프트 빌더 + diff 축소 (62줄)
│ └── providers/
│ ├── AIProvider.js # 추상 베이스 클래스 (14줄)
│ ├── registry.js # 프로바이더 레지스트리 (26줄)
│ ├── parse.js # AI 응답 파서, 3단계 fallback (61줄)
│ ├── claude.js # Claude API 구현 (59줄)
│ └── openai.js # OpenAI API 구현 (59줄)
├── package.json
├── README.md
├── README.ko.md
├── test/
│ ├── parse.test.js # 응답 파싱
│ ├── providers.test.js # 프로바이더 계약 + 오류 경로
│ └── safety.test.js # 셸 안전성, 대용량 diff, 키 격리
├── docs/archive/2026-03/ # PDCA 기록: plan → design → analysis → report
├── .github/workflows/ci.yml
└── .gitignore
총 ~749줄, 소스 파일 9개, 테스트 약 239줄. 런타임 의존성 4개.
npm test24개 테스트, 테스트 프레임워크 없이 내장 node --test만 씁니다. CI가 Ubuntu·Windows에서 Node 20·22·24로 돌립니다.
커버리지를 채우기보다, 실제로 물렸던 실패 지점에 의도적으로 무게를 뒀습니다.
| 테스트 | 막아둔 회귀 |
|---|---|
| 커밋 메시지가 셸에서 평가되지 않음 | execSync + JSON 이스케이프가 POSIX 셸에서 $(...)를 실행시켰음 |
| 1MB 초과 staged diff를 읽음 | 기본 maxBuffer 1MB가 lockfile 재생성 하나에 터졌음 |
| 환경변수 키가 디스크에 안 남음 | 설정 마법사가 환경변수 전용 키를 설정 파일에 되썼음 |
| 서문이 제안 목록에 안 들어감 | Here are 3 commit messages: 가 1번 제안이 됐음 |
| 빈/필터링된 API 응답 처리 | 무방비 content[0].text 가 정체불명 TypeError를 냈음 |
이 테스트들은 실제 효과를 검증합니다 — 셸 테스트는 임시 저장소에 페이로드를 커밋한 뒤 파일 시스템을 확인하고, diff 테스트는 실제로 1MB 넘는 diff를 만들어 돌립니다.
| 카테고리 | 선택 | 이유 |
|---|---|---|
| 런타임 | Node.js >= 20 (ESM) | 네이티브 fetch, 빌드 단계 없음 |
| CLI | Commander v12 | 경량, 표준 CLI 파싱 |
| 인터랙션 | Inquirer v9 | 풍부한 대화형 프롬프트 (select, password, confirm) |
| 스타일링 | chalk v5 + ora v8 | 터미널 색상 + 스피너 |
| AI API | 네이티브 fetch (SDK 없음) |
추가 의존성 제로, 프로바이더 간 일관된 패턴 |
| 테스트 | node --test (내장) |
테스트 프레임워크 의존성 없음 |
MIT