Conventional Commits - 커밋 메시지의 컨벤션 가이드

StrayCat·2026년 3월 18일

CS지식

목록 보기
24/32

본 포스팅은 Conventional Commits 스펙(specification, 명세)을 처음 접하는 개발자를 위해,
개념부터 실제 툴체인(toolchain, 개발 도구들의 연결 체계) 설정까지 정리한 내용이다.


팀 프로젝트를 하거나 오픈소스 저장소를 돌아보면, 커밋 히스토리가 이런 식인 경우를 발견할 수 있다. (컨벤션이 없거나, 개인적으로 하거나...등등)

fix
update
asdf
수정
진짜 마지막 수정

읽는 사람 입장에서는 아무런 정보가 없다. 무엇을 고쳤는지, 왜 고쳤는지, 이게 기능 추가인지 버그 수정인지조차 모른다. 히스토리가 길어질수록, 팀원이 많아질수록 이 문제는 더 심각해진다.

Conventional Commits는 이 문제를 해결하기 위해 만들어진 커밋 메시지 작성 규약(convention) 이다.


Conventional Commits란?

Conventional Commits는 커밋 메시지에 구조화된 포맷을 적용하는 경량 스펙이다. 2017년 Angular 팀의 커밋 컨벤션에서 영감을 받아 만들어졌으며, 현재는 독립적인 스펙으로 관리되고 있다.

핵심 아이디어는 간단하다.

커밋 메시지에 타입(type) 을 명시해서, 이 변경이 무엇인지를 기계와 사람 모두가 이해할 수 있게 만들자.

2025년 Wikipedia 분석 결과에 따르면, 인기 있는 NPM 프로젝트 381개 중 약 94.5%가 Conventional Commits 형식의 커밋을 포함하고 있을 만큼 특히 JavaScript/TypeScript 생태계에서 사실상 표준으로 자리잡은 상태다.


기본 구조

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

각 요소를 하나씩 살펴보자.

type (필수)

이 커밋이 어떤 종류의 변경인지를 나타낸다.

type설명SemVer 영향
feat새로운 기능 추가MINOR 버전 증가
fix버그 수정PATCH 버전 증가
docs문서만 변경없음
style코드 동작에 영향 없는 포맷팅 (세미콜론, 공백 등)없음
refactor기능 추가도 버그 수정도 아닌 코드 개선없음
test테스트 추가 또는 수정없음
chore빌드 프로세스, 패키지 매니저 설정 등없음
perf성능 개선없음
build빌드 시스템 또는 외부 의존성 변경없음
ciCI/CD 설정 변경없음

스펙 공식 필수 타입은 featfix 두 가지뿐이다. 나머지는 Angular 컨벤션에서 가져온 권장 타입으로, 대부분의 팀이 이 세트를 함께 사용한다.

scope (선택)

어느 모듈/영역이 변경됐는지를 괄호 안에 표시한다.

feat(auth): add OAuth2 login support
fix(user-api): handle null response from profile endpoint
docs(readme): update installation guide

scope는 팀마다 다르게 정의한다. 중요한 건 한 번 정한 scope 이름을 일관성 있게 사용하는 것이다.

description (필수)

변경 사항을 명령형(imperative mood) 으로, 짧게 요약한다.

# ❌ 과거형/현재진행형
fixed the login bug
fixing the login bug

# ✅ 명령형
fix login token expiry not being handled

영어로 작성하는 경우, 첫 글자는 소문자로 시작하고 마침표를 붙이지 않는 것이 일반적이다.

body (선택)

왜 이 변경을 했는지, 어떤 방식으로 해결했는지를 자유롭게 적는다. description과 빈 줄로 구분한다.

이슈 번호 참조, Breaking Change 명시 등에 사용한다.


Breaking Change — 가장 중요한 표현 방식

하위 호환성이 깨지는 변경(Breaking Change)은 두 가지 방법으로 표시한다.

방법 1 — ! 접미사 (권장)

feat(api)!: change user ID from integer to UUID

방법 2 — footer에 BREAKING CHANGE: 명시

feat(api): change user ID from integer to UUID

BREAKING CHANGE: user ID type has changed from integer to UUID.
Existing clients must update their integration accordingly.

Breaking Change가 포함된 커밋은 MAJOR 버전을 증가시킨다. (e.g., 1.2.32.0.0)


SemVer(Semantic Versioning)와의 연결

Conventional Commits가 강력한 이유 중 하나가 바로 시맨틱 버저닝(SemVer) 과의 연계다.

SemVer는 MAJOR.MINOR.PATCH 형식의 버전 번호 규칙이다.

1.4.2
│ │ └── PATCH: 버그 수정, 하위 호환 유지
│ └──── MINOR: 새 기능 추가, 하위 호환 유지  
└────── MAJOR: 하위 호환 불가능한 변경

Conventional Commits의 타입은 이 세 단계와 직접 매핑된다.

커밋 타입버전 변화예시
fix:1.0.01.0.1PATCH
feat:1.0.01.1.0MINOR
feat!: 또는 BREAKING CHANGE1.0.02.0.0MAJOR

이 매핑 덕분에 커밋 히스토리만 보면 다음 버전이 얼마나 올라가야 하는지를 자동으로 판단할 수 있다.


실전 예시들

단순한 것부터 복잡한 것까지 몇 가지 예시를 보자.

버그 수정 (단순)

fix(auth): resolve JWT token not refreshing on expiry

기능 추가 (scope + body)

feat(payment): add KakaoPay integration

Implements KakaoPay payment gateway using their REST API v2.
Supports single payment and subscription billing.

Breaking Change

feat(user)!: remove deprecated `username` field from response

BREAKING CHANGE: The `username` field has been removed from the User API response.
Use `email` as the unique identifier instead.
Refs: #204

문서 수정

docs(api): add rate limiting section to README

리팩토링

refactor(order): extract price calculation to separate service class

툴체인 — 자동화의 진짜 가치

규칙을 손으로만 지키는 건 한계가 있다. 팀원 모두가 컨벤션을 지키게 하려면 자동화 도구가 필요하다.

Conventional Commits 생태계에서 자주 사용하는 도구들을 정리하면 다음과 같다.

1. commitlint — 커밋 메시지 린터(linter)

커밋 메시지가 컨벤션을 따르는지 검사한다.

# 설치
npm install -D @commitlint/cli @commitlint/config-conventional
// commitlint.config.js
module.exports = {
  // Angular 컨벤션 기반의 공식 룰셋 확장
  extends: ['@commitlint/config-conventional'],
};

2. Husky — Git Hook 관리 도구

Git 훅(hook, 특정 Git 이벤트 발생 시 자동으로 실행되는 스크립트)을 쉽게 설정하고 팀 전체에 공유할 수 있게 해준다.

# 설치 및 초기화
npm install -D husky
npx husky init
# commit-msg 훅 추가 — 커밋 시마다 commitlint 실행
echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msg

이 설정이 완료되면, 컨벤션에 맞지 않는 커밋 메시지를 입력했을 때 다음과 같이 차단된다.

$ git commit -m "update stuff"

⧗  input: update stuff
✖  subject may not be empty [subject-empty]
✖  type may not be empty [type-empty]
✖  found 2 problems, 0 warnings

husky - commit-msg hook exited with code 1 (error)

3. Commitizen — 커밋 메시지 작성 보조 CLI

타입을 까먹거나 형식이 헷갈리는 경우, 대화형 CLI로 커밋 메시지를 작성하게 도와주는 도구다.

npm install -D commitizen cz-conventional-changelog
npx commitizen init cz-conventional-changelog --save-dev --save-exact

git cz 또는 npx cz 명령어 실행 시 다음과 같은 프롬프트가 나타난다.

? Select the type of change that you're committing:
❯ feat:     A new feature
  fix:      A bug fix
  docs:     Documentation only changes
  style:    Changes that do not affect the meaning of the code
  refactor: A code change that neither fixes a bug nor adds a feature
  perf:     A code change that improves performance
  test:     Adding missing tests or correcting existing tests

VS Code를 사용한다면 Conventional Commits 확장 프로그램도 같은 역할을 GUI로 제공한다.

4. semantic-release — 자동 버전 관리 및 릴리즈

커밋 히스토리를 분석해서 다음 버전을 자동으로 결정하고, CHANGELOG를 생성하며, GitHub Release나 npm 배포까지 자동화하는 도구다.

feat: add dark mode support        → 1.0.0 → 1.1.0 (MINOR)
fix: fix button color in dark mode → 1.1.0 → 1.1.1 (PATCH)
feat!: redesign theme API          → 1.1.1 → 2.0.0 (MAJOR)

CI/CD 파이프라인(빌드, 테스트, 배포를 자동화하는 흐름)에 연결하면, main 브랜치에 머지되는 순간 릴리즈가 자동으로 실행된다.


전체 흐름 한눈에 보기

개발자가 코드 작성
       ↓
git commit 실행
       ↓
Husky의 commit-msg 훅 트리거
       ↓
commitlint가 메시지 포맷 검사
       ↓  (통과 실패 시 커밋 차단)
커밋 저장소에 기록
       ↓
PR 머지 → main 브랜치 업데이트
       ↓
CI에서 semantic-release 실행
       ↓
커밋 타입 분석 → 버전 자동 결정
       ↓
CHANGELOG.md 자동 생성 + GitHub Release 생성

레거시 환경에서는 어떻게?

현실에서는 이미 수천 개의 커밋이 쌓인 기존 레거시 저장소에서 작업하는 경우도 많다. 이때는 다음과 같이 접근하는 것이 현실적이다.

  • 과거 커밋은 건드리지 않는다. 히스토리 재작성(rebase)은 협업 중인 저장소에서 위험하다.
  • "오늘부터" 적용한다. 팀 내 합의 후 Contributing 가이드에 명시하고, 신규 커밋부터 적용한다.
  • CI 검사는 PR 단위로만 먼저 시작한다. 로컬 훅은 팀원별로 설정해야 해서 누락될 수 있지만, CI에서 PR 커밋을 검사하면 머지 시점에 한 번 더 보장된다.

정리

도입 전도입 후
커밋 히스토리의미 없는 메시지 나열변경 의도가 명확히 기록됨
버전 관리수동 결정, 팀원 간 의견 충돌커밋 타입 기반 자동 결정
CHANGELOG수동 작성 또는 생략자동 생성
코드 리뷰PR 설명을 따로 봐야 함커밋 메시지 자체가 문서 역할

처음에는 타입을 뭘 써야 할지 헷갈리고, featrefactor의 경계가 모호하게 느껴질 수 있다. 하지만 팀 내 기준을 Contributing 가이드에 명시하고, 린터(linter)가 형식만 잡아준다면 생각보다 빠르게 익숙해진다.

커밋 메시지 하나하나가 프로젝트의 역사가 된다. 미래의 팀원(또는 미래의 나)이 git log를 켰을 때 의미 있는 정보를 줄 수 있는 히스토리를 만드는 것, 그게 Conventional Commits의 핵심이다.


참고 자료

profile
알면 좋은 것보단 잊어버리기 싫은 것들을 기록합니다.

0개의 댓글