Conventional Commits란?
Conventional Commits는 커밋 메시지를 일정한 형식으로 작성하는 규칙이다.
목적은 커밋 메시지에 사람이 읽을 수 있는 의미와 도구가 해석할 수 있는 의미를 함께 담는 것이다.
예를 들어 다음 커밋 메시지는 단순히 "수정했다"가 아니라, 어떤 종류의 변경인지 명확히 알려준다.
fix: handle empty search query
또 다른 예시는 다음과 같다.
feat: add post search
이렇게 작성하면 커밋 기록을 읽기 쉬워지고, changelog 생성이나 버전 계산 같은 자동화도 가능해진다.
기본 형식
Conventional Commits의 기본 형식은 다음과 같다.
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
가장 단순한 형태는 다음과 같다.
feat: add login form
scope를 포함하면 다음처럼 작성한다.
feat(auth): add login form
본문과 footer를 포함하면 다음과 같은 형태가 된다.
fix(search): ignore blank keyword
Return an empty result when the query only contains spaces.
Refs: #123
type
type은 커밋의 종류를 나타낸다.
공식 스펙에서 의미가 명확히 정의된 핵심 type은 feat와 fix이다.
| type | 의미 | SemVer 영향 |
|---|---|---|
fix | 버그 수정 | PATCH |
feat | 새로운 기능 추가 | MINOR |
BREAKING CHANGE | 호환성이 깨지는 변경 | MAJOR |
예를 들어 버그 수정은 다음처럼 작성한다.
fix: prevent duplicate submit
새 기능 추가는 다음처럼 작성한다.
feat: add dark mode toggle
자주 쓰는 type
feat와 fix 외에도 여러 type을 사용할 수 있다.
Conventional Commits 스펙이 모든 type을 강제하지는 않지만, 일반적으로 다음 type들이 많이 쓰인다.
| type | 의미 |
|---|---|
docs | 문서 수정 |
style | 포맷팅, 스타일 수정 |
refactor | 동작 변화 없는 코드 구조 개선 |
test | 테스트 추가 또는 수정 |
chore | 빌드, 설정, 기타 작업 |
build | 빌드 시스템 또는 의존성 변경 |
ci | CI 설정 변경 |
perf | 성능 개선 |
예시는 다음과 같다.
docs: update README
style: format markdown files
refactor: simplify category label rendering
test: add parser tests
chore: update dependencies
ci: add build workflow
scope
scope는 변경 범위를 나타낸다.
scope는 type 뒤에 괄호로 작성한다.
fix(parser): handle empty token
feat(search): add fuzzy matching
docs(api): add request example
scope는 필수가 아니다.
하지만 프로젝트가 커질수록 scope가 있으면 어떤 영역이 바뀌었는지 빠르게 파악할 수 있다.
예를 들어 블로그 프로젝트라면 다음과 같은 scope를 사용할 수 있다.
post
category
search
layout
theme
seo
description
description은 커밋 내용을 짧게 설명하는 부분이다.
fix(search): handle empty query
여기서 handle empty query가 description이다.
좋은 description은 다음 성질을 가진다.
- 짧다.
- 변경 의도가 드러난다.
- 너무 추상적이지 않다.
나쁜 예시는 다음과 같다.
fix: update
무엇을 고쳤는지 알기 어렵다.
더 나은 예시는 다음과 같다.
fix: handle missing post image
body
body는 커밋에 대한 추가 설명이다.
description만으로 충분하지 않을 때 사용한다.
fix(search): ignore blank keyword
Previously, a blank query still triggered search ranking.
This change returns the default post list for blank input.
body에는 보통 다음 내용을 적는다.
- 왜 변경했는가?
- 이전 동작은 무엇이었는가?
- 어떤 방식으로 해결했는가?
- 주의해야 할 점은 무엇인가?
모든 커밋에 body가 필요한 것은 아니다.
간단한 커밋은 한 줄 메시지만으로 충분하다.
footer
footer는 이슈 번호, 리뷰어, breaking change 같은 메타데이터를 적는 영역이다.
예시는 다음과 같다.
fix(search): prevent duplicate results
Refs: #123
Reviewed-by: kim
가장 중요한 footer는 BREAKING CHANGE이다.
feat(api): change response format
BREAKING CHANGE: response now wraps data in a result field
이 커밋은 기존 API 사용자에게 영향을 주는 변경이다.
SemVer 기준으로는 MAJOR 버전 변경에 해당한다.
Breaking Change
호환성이 깨지는 변경은 두 가지 방식으로 표현할 수 있다.
첫 번째는 footer에 BREAKING CHANGE를 적는 방식이다.
feat(config): change config loading order
BREAKING CHANGE: environment variables now override config files
두 번째는 type 또는 scope 뒤에 !를 붙이는 방식이다.
feat!: drop support for Node 16
scope와 함께 쓸 수도 있다.
feat(api)!: change user response format
!는 이 커밋이 breaking change라는 것을 제목에서 바로 드러낸다.
SemVer와의 관계
Conventional Commits는 SemVer(Semantic Versioning)와 잘 맞는다.
기본 대응은 다음과 같다.
fix -> PATCH
feat -> MINOR
BREAKING CHANGE -> MAJOR
예를 들어 현재 버전이 1.2.3이라고 하자.
fix 커밋만 있으면 다음 버전은 보통 1.2.4가 된다.
1.2.3 -> 1.2.4
feat 커밋이 있으면 minor version이 올라간다.
1.2.3 -> 1.3.0
breaking change가 있으면 major version이 올라간다.
1.2.3 -> 2.0.0
이 규칙 덕분에 커밋 메시지만 보고도 changelog와 버전 변경을 자동화할 수 있다.
좋은 예시
feat(category): add compact labels
카테고리 기능이 추가되었고, 변경 범위가 category임을 알 수 있다.
fix(post): handle missing thumbnail
글 카드의 썸네일 누락 문제를 고쳤음을 알 수 있다.
docs(git): add git flow notes
Git 관련 문서를 추가한 커밋이다.
refactor(search): simplify ranking logic
검색 랭킹 로직의 동작은 유지하면서 내부 구조를 개선한 커밋이다.
좋지 않은 예시
update
type이 없고 무엇을 바꿨는지 알기 어렵다.
fix stuff
형식이 맞지 않고, 설명도 모호하다.
feat: change files
새 기능인지, 어떤 파일인지, 어떤 의도인지 알기 어렵다.
fix: bug
어떤 버그를 고쳤는지 정보가 부족하다.
실전 기준
개인 프로젝트라면 너무 복잡하게 시작할 필요는 없다.
처음에는 다음 type만 사용해도 충분하다.
feat
fix
docs
style
refactor
test
chore
예를 들어 블로그 글을 추가하면 다음처럼 작성할 수 있다.
docs(post): add git flow article
UI 스타일을 수정하면 다음처럼 작성할 수 있다.
style(category): refine compact labels
코드 구조를 정리했지만 동작이 바뀌지 않았다면 다음처럼 작성한다.
refactor(search): split ranking helpers
정리
Conventional Commits의 핵심은 다음 형식이다.
<type>[optional scope]: <description>
가장 중요한 type은 다음 세 가지다.
fix -> bug fix
feat -> new feature
BREAKING CHANGE -> breaking API change
커밋 메시지를 규칙적으로 작성하면 다음 장점이 있다.
- 커밋 기록을 읽기 쉬워진다.
- 변경 의도가 명확해진다.
- changelog 생성을 자동화할 수 있다.
- SemVer 기반 버전 계산이 쉬워진다.
- 협업자가 변경 내용을 빠르게 이해할 수 있다.
결국 Conventional Commits는 커밋 메시지를 단순 기록이 아니라 변경사항을 설명하는 구조화된 문서로 만드는 방법이다.