Commit History를 효과적으로 관리하기 위한 규약: Conventional Commits

Joonho Yeom
RIZON Korea
Published in
10 min readFeb 15, 2020

이번에는 우리가 개발을 어떻게 진행하고 있는지 공유하는 첫번째 글을 작성해보려고 합니다. 프로젝트를 처음 시작하며 Commit Message를 어떻게 남기는 것이 좋을지 팀원들과 이야기를 나누어 보았었습니다. Commit Message Format을 크게 신경쓰지 않는 프로젝트들도 많지만, 나름의 규칙을 지닌 프로젝트들도 있습니다.

우리는 Conventional Commits 를 프로젝트에 도입해 보기로 했고, 그 과정에서 들었던 생각과 느낌을 공유해 보고자 합니다.

좋은 Commit Message란 무엇일까?

우리는 의미 단위로 코드 뭉치를 작성하고, VCS(Version Control System)에 snapshot을 찍는 행위를 Commit이라고 부릅니다. 그리고 Commit을 할 때마다 그것을 설명하는 Message를 남기게끔 되어있습니다. 작성한 Commit Message는 우리가 작성한 코드의 의미를 이해하는 단서가 되기도 하고, 프로젝트 개발의 흐름과 방향을 가늠해볼 수 있게 하기도 합니다. 이러한 용도를 고려해 볼 때 Message는 큰 흐름에서 보았을 때 Commit의 내용을 쉽게 파악할 수 있도록 간명해야 하고, 작성한 코드의 의미를 잘 설명해 주어야 한다는 것을 짐작해볼 수 있습니다.

그렇다면 좋은 Commit Message는 어떻게 작성해야 할까요? Linus Tovalds는 좋은 Commit Message에 대해서 다음과 같이 설명합니다. link

Header line: explain the commit in one line (use the imperative)Body of commit message is a few lines of text, explaining things    in more detail, possibly giving some background about the issue    being fixed, etc etc.The body of the commit message can be several paragraphs, and    please do proper word-wrap and keep columns shorter than about
74 characters or so. That way "git log" will show things
nicely even when it's indented.
Make sure you explain your solution and why you're doing what
you're doing, as opposed to describing what you're doing.
Reviewers and your future self can read the patch, but might
not understand why a particular solution was implemented.
Reported-by: whoever-reported-it
Signed-off-by: Your Name <youremail@yourhost.com>

Example 1-Linus’ Recommendation

Commit Message를 Header, Body 그리고 Footer 형태로 나누고, Header에는 Commit의 한 줄 요약을 명령문 형태로 작성합니다. Body에는 어떻게 구현했는지를 서술하는 것이 아니라, Issue에 대한 Background와 자신의 Solution 그리고 왜 이렇게 구현했는지 작성합니다. 마지막으로 Footer에는 Reporter와 Signer를 기록합니다.

이처럼 Message Format을 지정함으로써 개발자들은 어떤 형태로 Commit Message를 작성해야 하는지 고민하지 않아도 되고, Commit Message가 포함해야 하는 내용을 개발자들이 잘 작성하도록 유도할 수 있습니다.

Linus’ Commit Message 작성 방식은 다양한 Commit Message Format에 영향을 주었고 우리 팀은 그 중에 Conventional Commits 라는 규약을 선택하기로 하였습니다.

Conventional Commits란?

Conventional CommitsAngular Commit Guideline에서 영감을 받아 작성된 Commit Message Specification입니다. 이 Specification의 목적은 개발자들이 SemVer 와 들어맞도록 Commit Message를 작성하도록 해, 프로젝트의 Semantic Version을 자동으로 결정하고, production Release시에 CHANGELOG 를 자동으로 생성하는 것 입니다. Conventional Commit Message는 아래와 같은 형태로 작성합니다.

<type>(<optional scope>): <subject>
<BLANK LINE>
<optional body>
<BLANK LINE>
<optional footer>

Example 2-Conventional Commit Message Format

Message를 작성하는 법

  • fix: 기존 기능의 변경 없이 bug를 고치는 경우에 사용하는 type입니다. Semantic VersionPATCH에 대응하는 Message Type입니다.
  • feat: 기능의 변경 및 추가가 되는 경우에 사용하는 type입니다. Semantic VersionMINOR에 대응하는 Message Type입니다.
  • BREAKING CHANGE: optional Body나 optional footer를 BREAKING CHANGE: 라는 text로 시작하면 이것은 기존 API와의 호환성을 지키지 않게 됨을 의미합니다. Semantic VersionMAJOR에 대응하고 어느 Message Type에도 적용할 수 있습니다. Commit Message가 BREAKING CHANGE를 포함하고 있는지 Headline만 보고도 쉽게 확인 할 수 있도록 선택적으로 !를 포함 시킬 수 있습니다.
  • fix와 feat이 아닌 다른 type들을 추가해 사용할 수 있고 보편적으로 [build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test]가 많이 사용됩니다. 참고로, 이 type들을 의무적으로 사용해야 하는 것은 아닙니다. 프로젝트들은 자신들에게 알맞은 type set 및 scope set을 각자 정의해 사용할 수 있습니다.
fix(release): need to depend on latest rxjs and zone.jsThe version in our package.json gets copied to the one we publish, and users need the latest of these.

Example 3-Conventional Commit Message Sample with optional scope

Example 3은 fix type이므로 Semantic VersionPATCH 에 해당하는 변화를 의미합니다.

chore!: drop Node 6 from testing matrixBREAKING CHANGE: dropping Node 6 which hits end of life in April

Example 4-Conventional Commit Message Sample with BREAKING CHANGE

Example 4는 Body가 BREAKING CHANGE:로 시작하므로 Semantic VersionMAJOR에 해당하는 변화를 의미합니다. BREAKING CHANGE가 body에 있음을 Headline에 표시하기 위해 type과 colon사이에 ! 를 삽입하였습니다.

feat(docs-infra): add v8 to the version picker in the navbar(#35196)The v8.angular.io should be ready shortly.PR Close #35196

Example 5-Conventional Commit Message Sample with optional footer

Close #123과 같은 meta-information은 Example 5처럼 footer에 작성합니다.

Conventional Commit Message에 대한 전체 Specification은 link 를 따라가면 확인할 수 있습니다.

Conventional Commits의 장점

Conventional Commit Message를 사용한 Repository의 Commit History
  • Type과 Scope 덕분에 Commit History Tree를 훑어보는 것 만으로 어떤 범위에 어떤 성격의 변경이 반영되었는지 쉽게 파악할 수 있습니다.
  • Message Format에 맞추어 작성하다 보면, 개발자들이 의미를 의식해 Commit 하게 되어 전반적인 Code의 질을 높이는 효과가 있습니다.
    * Message가 구체적인 한 Headline에 대해 작성하도록 요구하기 때문에 하나의 Commit속 Code의 의미가 분명해지도록 작성하게 되는 효과가 있습니다.
    * fix나 feature등 성격이 다른 것들을 가능한 분리해서 Commit하게 됩니다.
  • Versioning, CHANGELOG를 관리하는 부담을 줄일 수 있습니다.
    * Commit Message를 type에 따라 Parsing하는 Script를 이용해 CHANGELOG를 생성할 수 있게 됩니다.
    * 개발자가 Commit을 할 때마다 Semantic Version에 해당하는 Type을 직접 기록하기 때문에 Versioning 실수를 최소화 할 수 있고, Breaking Change가 존재하는지, feature가 추가되었는지를 누군가 수동으로 관리할 필요가 없게 됩니다.

Conventional Commits과 함께 사용할 수 있는 유용한 Tool들

  • Linter
    * Commit Message에 대한 Lint를 제공합니다.
    * Web 형태로도 사용할 수 있고 CLI 형태로도 사용할 수 있습니다.
    *Angular Commit Convention을 기본 설정으로 동작하고 Convention을 커스터마이징해서 lint할 수 있습니다.
  • conventional-changelog-cli
    * git metadata로부터 CHANGELOG를 생성해주는 CLI 도구
  • Semantic Release
    * semantic-release를 자동화해주는 도구, Angular Commit Convention을 기본 설정으로 동작하고 설정을 커스터마이징 할 수 있습니다.

앞으로 더 풍성하고 다양한 주제로 글을 올릴 예정입니다. 많이 기대해주세요 :)

References

--

--