본문으로 건너뛰기

© 2026 Molayo

HN분석2026. 06. 06. 03:09

Conventional Commits는 잘못된 것에 집중하게 만든다

요약

Conventional Commits 표준이 변경의 유형(type)을 범위(scope)보다 우선시하는 구조적 결함을 지적합니다. 기여자, 디버거, 장애 대응자에게 가장 중요한 정보는 변경된 영역인 '범위'임을 강조하며 현재 표준의 문제점을 비판합니다.

핵심 포인트

  • Conventional Commits는 유형보다 범위가 더 중요한 정보를 담고 있음
  • 기여자는 코드베이스의 변화 방향을 파악하기 위해 범위를 우선 확인함
  • 디버거와 장애 대응자에게는 변경 유형보다 수정된 영역 식별이 필수적임
  • 현재의 표준은 실제 개발 워크플로우의 우선순위와 역행함

**게시됨
Software Engineering 분야에서
**• 1873 단어
• 읽기 시간 9분

태그:
Git, Commits, Scoped Commits, Conventional Commits

여러분은 아마도 이전에 Conventional Commits를 접해본 적이 거의 확실히 있을 것입니다.
여러분이 사용해 온 오픈 소스 프로젝트의 변경 로그(changelog)에서 그 못생긴 모습을 보았을 수도 있습니다. 여러분이 기여했던 오픈 소스 프로젝트에서 강제된 커밋 형식이었을 수도 있습니다. 많은 사람들이 이를 신봉하지만, 저는 이를 비난합니다.

많은 인기 오픈 소스 프로젝트에서 사용되고 있음에도 불구하고, Conventional Commits는 잘못된 것에 집중하게 만들고 그 약속을 이행하지 못하는 적극적으로 나쁜 표준입니다.

Conventional Commits는 개발자와 최종 사용자가 커밋에서 이루어진 변경 사항을 이해하는 데 도움을 주기 위해 커밋 메시지에 의미론적 의미 (semantic meaning)를 추가하겠다고 약속합니다. 하지만 Conventional Commits는 이를 아주 처참하게 실패합니다. 이를 증명하기 위해, Conventional Commit의 구조를 살펴보겠습니다. Conventional Commit 웹사이트에 따르면 커밋 메시지는 다음과 같이 형식을 갖추어야 합니다:

<type>[optional scope]: <description>
[optional body]
[optional footer(s)]

커밋의 제목 줄에는 변경 유형을 설명하는 <type> (fix, feat, chore, docs, 또는 refactor와 같은 것)이 있습니다. 그 뒤에는 선택적인 범위 (scope)가 오고, 그 다음에는 설명 (description)이 옵니다.

이 형식에는 중대한 결함이 있습니다: 범위 (scope)보다 유형 (type)이 우선시된다는 점입니다. 이것은 정확히 거꾸로 되었습니다.

변경의 범위 (scope) (변경의 대상)는 커밋에서 가장 중요한 부분입니다. 이를 증명하기 위해, 다음의 각 이해관계자들이 왜 변경의 유형보다 변경의 범위에 더 관심을 갖는지 살펴보겠습니다:

기여자 (Contributors): 프로젝트의 기여자로서 활동할 때, 특정 코드 영역과 관련된 코드베이스의 변경 사항을 식별하기 위해 커밋 로그 (commit log)를 읽어야 하는 경우가 많습니다. 여기에는 다음과 같은 많은 이유가 있습니다:

  • 마지막으로 기여한 이후에 어떤 일이 일어났는지 파악하고 싶을 때.
  • 프로젝트의 전반적인 관성 (inertia)이 어디로 향하고 있는지 이해하려고 할 때.
  • pull 또는 rebase를 수행할 때 현재 진행 중인 작업과 충돌할 수 있는 커밋을 찾을 때.

커밋 로그를 읽을 때, 여러분은 *어떤 영역 (what areas)*이 수정되었는지를 보고 있습니다. 여러분은 실제로 어떤 *유형 (type)*의 변경이 일어나는지에는 관심이 없으며, 변경의 *범위 (scope)*에 관심을 가집니다.

디버거 (Debuggers): 버그를 조사할 때, 버그가 나타난 컴포넌트와 관련된 영역을 건드렸을 법한 변경 사항을 확인하기 위해 커밋 로그를 살펴보는 경우가 많습니다. 다시 한번 말하지만, 범위 (scope)가 가장 중요한 정보입니다. 변경의 유형 (type)은 완전히 무용지물인데, 버그는 유형에 관계없이 어떤 변경 사항에서도 발생할 수 있기 때문입니다. (우리 모두 버그 수정을 작성했다가 또 다른 버그를 유발했던 경험이 있을 것입니다.)

장애 대응자 (Incident responders): 운영 환경이 다운되었을 때, 장애 발생 시간 전후로 이루어진 변경 사항을 커밋 로그에서 스캔하는 것은 어떤 영역이 문제를 일으키고 있는지 식별하는 효과적인 방법입니다. 이 시점에서 여러분이 가질 수 있는 가장 중요한 정보는 다시 한번 범위 (scope)입니다. 예를 들어, 유입되는 API 에러가 급증하는 시점에 auth 범위와 관련된 커밋이 보인다면, 그것이 문제의 유력한 원인일 가능성이 높습니다. 그리고 다시 한번 강조하지만, 유형 (type)은 무관합니다. 어떤 변경 사항에 의해서든 버그가 추가될 수 있기 때문입니다.

그렇다면 Conventional Commits는 무엇을 하고 있나요? 그것은 범위 (scope)의 우선순위를 너무 낮추어서 아예 *선택 사항 (optional)*으로 만들어 버렸습니다! 왜 도대체 *범위 (scope)*가 선택 사항인 걸까요? 범위가 없는 커밋을 갖는 것은 주어가 없는 문장을 갖는 것과 같습니다! 게다가 설상가상으로, Conventional Commits는 *유형 (type)*을 커밋 메시지의 맨 앞으로 격상시켰습니다. Conventional Commits는 범위 (scope)와 유형 (type)의 우선순위를 완전히 잘못 파악하고 있습니다.

여러분은 “그럼 순서가 바뀌었을지언정, 커밋 유형 (commit type)은 여전히 중요하겠지?”라고 생각할지도 모르겠습니다. 이에 대해 저는 “아니오”라고 답하겠습니다. 커밋의 설명 (description)은 거의 항상 변경의 유형을 알려주어야 합니다! 다음 커밋 메시지를 예로 들어보겠습니다:

fix(compiler): prevent namespaced SVG <style> elements from being stripped

설명만 있더라도 이것이 버그 수정 (bugfix)이라는 점은 명백합니다! 커밋의 제목 줄 (subject line) 공간은 이미 매우 귀중하며, 유형에 글자 수를 낭비하는 것은 도움이 되지 않습니다! 하지만 이는 단순히 무용지물인 것을 넘어, 종종 제한적이기까지 합니다. 다음 커밋 메시지를 예로 들어보겠습니다:

refactor(core): Update webmcp support to use document.modelContext

이 커밋은 core 컴포넌트 내의 webmcp 기능을 document.modelContextnavigator.modelContext를 모두 지원하도록 업데이트했습니다. 그렇다면 이것은 버그 수정 (bugfix)일까요, 리팩터링 (refactor)일까요, 아니면 새로운 기능 (new feature)일까요? 저는 이 세 가지 모두라고 주장하겠습니다! 하지만 다시 말하지만, 정말로 중요한 유일한 사실은 이것이 core/webmcp 컴포넌트에 대한 변경이었다는 점입니다.

Conventional Commits는 근본적으로 잘못된 것(커밋 유형)에 집중하며, 사람들이 실제로 관심을 갖는 것(범위 (scope))의 가치를 떨어뜨립니다.

따라서 우리는 Conventional Commits의 형식이 형편없다는 것을 확인했지만, 이것이 어떠한 이점이라도 제공해야 합니다. Why Use Conventional Commits 섹션을 읽어보며 그 이유 중 납득할 만한 것이 있는지 살펴보겠습니다.

CHANGELOG 자동 생성. 이것이 Conventional Commits의 가장 큰 약속입니다. git-cliff 또는 conventional-changelog와 같은 도구를 실행하여 마지막 릴리스 이후의 커밋으로부터 변경 로그 (changelog)를 생성할 수 있다는 것입니다. 이것이 과연 좋은 아이디어일까요? 아닙니다! 변경 로그의 대상은 커밋 로그의 대상과 완전히 다릅니다!

변경 로그는 사용자 지향적이며, 사용자는 버전 간의 기능적 차이를 이해하는 데 관심이 있습니다. 그들은 무엇이 변경되었는지에 관심을 가집니다.

비즈니스/기능적 (business/functional) 관점. 커밋 로그는 개발자 지향적이며, 개발자들은 코드베이스가 시간이 지남에 따라 어떻게 변해왔는지에 대한 이야기를 읽는 것에 관심을 가집니다. 그들은 무엇이 변경되었는지에 관심을 가집니다.

범위 (scope) 관점. 보시다시피, 이 두 가지는 완전히 다른 입도(grain)를 가지고 있으며, 이를 결합하려는 모든 시도는 수준 이하의 결과를 초래합니다. 그 이유는 여러 가지가 있습니다:

  • 어느 정도 복잡한 프로젝트에서든 주목할 만한 기능을 반영하기 위해서는 여러 번의 커밋이 필요합니다. (커밋 로그에 기록된 대로) 기능을 반영하는 과정은 개발자와 기여자들에게는 가치가 있지만, 최종 사용자에게는 무용지물입니다. 최종 사용자는 새로운 기능에만 관심이 있을 뿐, 그것이 어떻게 만들어졌는지에는 관심이 없습니다!
  • Rich가 지적했듯이, 되돌리기 (revert)는 Conventional Commits에서 문제가 됩니다. 되돌리기 커밋은 개발자 관점의 커밋 로그 이야기 측면에서는 중요하지만, 최종 사용자에게 되돌려진 변경 사항은 변경되지 않은 것과 동일합니다.

(반영된 커밋의 유형을 기반으로) 시맨틱 버전 (semantic version) 상승을 자동으로 결정하는 것. 이는 듣기에는 좋지만, 소프트웨어 엔지니어링의 현실은 이 작업을 정확하게 수행할 수 있는 생존 가능성을 종종 크게 저해합니다. 다음과 같은 상황들을 고려해 보십시오:

되돌리기 (Reverts): 당신이 도입한 파괴적 변경 (breaking change)이 너무나 파괴적이어서 반드시 되돌려야 하는 상황을 상상해 보십시오. 당신의 도구는 파괴적 변경을 감지하고 메이저 버전 (major version)을 올리겠지만, 실제로는 그 파괴적 변경이 되돌려졌으므로 파괴적 변경이 없는 상태입니다.

우발적 파괴 (Accidental breakages): 어쩌면 파괴가 미묘해서 변경을 수행할 당시에는 그것이 파괴적 변경인지 깨닫지 못할 수도 있습니다. 나중에 되돌아보고 나서야 그것이 파괴적임을 깨닫게 됩니다. 이 경우 메이저 버전 상승이 필요함에도 불구하고 마이너/패치 (minor/patch) 버전을 잘못 올리게 됩니다.

소급적 비파괴 (Retroactive unbreakages): 나중에 이전에 파괴적이었던 커밋과 결합하여 파괴적이지 않은 차이(diff)를 만드는 커밋을 추가한다고 가정해 봅시다. 되돌리기 상황과 마찬가지로, 도구는 이를 파괴적 변경으로 잘못 식별할 것입니다.

그러한 상황에서 rebase를 통해 히스토리(history)를 다시 작성할 수도 있지만, 이는 종종 워크플로(workflow)를 깨뜨리거나 워크플로에 의해 차단됩니다. 또한 프로젝트에 기여하려는 기여자들에게 수정주의적 역사(revisionist history)를 제시하게 되어, 커밋 로그(commit log)가 전달하는 이야기의 신뢰성을 떨어뜨립니다.

팀원, 대중 및 기타 이해관계자에게 변경의 성격을 전달하는 것. 지금까지 확인했듯이, 팀원과 대중은 변경 로그(changelog)와 커밋 로그(commit log)에 대해 매우 다른 요구사항을 가지고 있습니다. Conventional Commits는 이 중 어느 것도 해결하지 못합니다.

빌드 및 배포 프로세스(build and publish processes) 트리거. 이것은 그저 좋지 않은 생각입니다. 예를 들어, 코드를 수정하는 커밋에 대해서만 자동화된 보안 검사를 실행한다고 가정해 봅시다. 그런데 누군가 다음과 같은 제목으로 Trojan-horse(트로이 목마) 커밋을 생성한다면 어떨까요?

docs: fix typos

이 커밋이 실제로는 인증 서브시스템(authentication subsystem)에 취약점을 도입한다면 말입니다. 분명히 그러한 악의적인 활동은 코드 리뷰(code review)에서 포착되기를 바라겠지만, 자동화된 도구는 우회되었으며 문제를 식별해야 하는 책임이 인간에게 전가됩니다. 컴퓨팅 비용은 저렴하므로, 단순히 git diff를 사용하여 변경된 파일(다시 말하지만 scope)을 식별하고 이를 기반으로 빌드/배포 프로세스를 실행하십시오.

더 구조화된 커밋 히스토리를 탐색할 수 있게 함으로써 사람들이 프로젝트에 더 쉽게 기여할 수 있도록 하는 것. 더 구조화된 것은 맞습니다. 하지만 기여를 더 쉽게 만든다? 전혀 그렇지 않습니다 (이미 상세히 입증한 바와 같이).

Conventional Commits의 "판매 포인트(selling points)" 중 실제로 타당한 것은 단 하나도 없습니다.

Conventional Commits는 프로젝트에 적용하기도 매우 어렵습니다. 자신만의 "타입(types)" 세트를 정의해야 하지만, 거의 모든 사람이 commitlint의 기본값을 그대로 가져다 쓰며, 이는 종종 개별 프로젝트의 특성과 잘 맞지 않습니다. 이 문제는 변경 관리(change management) 및 감사(audit) 요구사항으로 인해 모든 커밋 메시지에 티켓 번호(ticket number)를 포함해야 하는 기업 환경에서 특히 심각합니다. <scope>

필드(field)가 이를 넣기에 가장 명백한 장소이지만, 이는 결국 Conventional Commit에서 유일하게 유용한 메타데이터를 완전히 쓸모없는 티켓 번호(ticket number)로 대체하는 결과를 초래합니다.

그렇다면 대신 무엇을 해야 할까요? Linux, FreeBSD, Git, Go, NixOS와 같이 진정으로 성공한 소프트웨어 프로젝트들의 선례를 따르십시오! 이 프로젝트들의 공통점은 무엇일까요? 이들은 모두 scope-prefixed 커밋 메시지(여기서 "scope"는 실제 프로젝트와 관련이 있는 것으로 정의됨)를 사용합니다. 보통 특정 프로젝트에서 사용할 scope는 자명합니다. Linux 커널의 경우, 서브시스템(subsystem)이 자연스러운 scope입니다. Go 프로젝트의 경우, 패키지 경로(package path)가 자연스러운 scope입니다. 마이크로서비스 아키텍처(microservice architecture)를 사용하는 프로젝트의 경우, 마이크로서비스 이름이 자연스러운 scope입니다.

다음은 몇몇 프로젝트와 그들의 커밋 형식 가이드라인 예시입니다.

프로젝트형식예시
Linuxsubsystem: descriptioni2c: virtio: mark device ready before registering the adapter
...

불행하게도, 역사상 가장 성공적인 오픈 소스 프로젝트 중 일부에서 사용되고 있음에도 불구하고, 이 커밋 스타일은 브랜딩 전쟁에서 패배한 것으로 보입니다. 저는 그것을 바꾸고자 합니다. scopedcommits.com을 소개합니다. 이 웹사이트는 커밋 메시지의 합리성(sanity)을 되찾고, 변경 로그 생성(changelog generation)의 관심사(concern)를 커밋 로그 관리(commit log management)로부터 분리하는 것을 옹호하는 데 전념합니다.

Conventional Commits가 주장하는 장점들은 사실 환상에 불과하며, 업계는 이를 표준으로 사용함으로써 어떠한 실질적인 이득도 얻지 못했습니다. 그러나 불행하게도 Conventional Commits는 오픈 소스 프로젝트들 사이에서 상당히 대중화된 것으로 보이며, 이로 인해 AI들이 커밋 메시지에 이를 기본값으로 사용하는 습관을 갖게 된 듯합니다. 이는 안티 패턴(anti-pattern)이 가득한 커밋 메시지들이 프로젝트 전반에 걸쳐 전파되는 결과를 초래했습니다.

이 글의 목표는 Conventional Commits의 지배력에 맞서 싸우고, 커밋 메시지를 구성하는 더 나은 방법들이 있음을 증명하는 것입니다. 하지만 이 글이 여러분으로 하여금 Conventional Commits 사용을 중단하도록 설득하지 못한다면, 댓글창에서 벌어질 논쟁(flame war)을 기대하겠습니다.

기술적으로 Conventional Commits 명세(specification)는 오직

fix

feat

만을 정의하며, 추가적인 타입(type)은 개별 프로젝트가 지정하도록 남겨둡니다. 하지만 대부분의 프로젝트는 결국 commitlint에 의해 정의된 타입들을 사용하게 되므로, 이 목록에 그중 일부를 포함했습니다. ↩︎

AI 자동 생성 콘텐츠

본 콘텐츠는 HN AI Posts의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0