😩 복잡해지는 커밋 히스토리
우리의 프로젝트는 시간이 흐르면 흐를수록 서비스는 더욱 복잡해지게 되고, 서비스가 복잡해진다는 것은 필연적으로 수많은 커밋이 존재하게 된다는 것을 의미합니다.
그런데, 커밋들을 되돌아보면서 수정할 사항을 파악한다거나, 프로젝트를 회고하는 등 다양한 정보를 파악해야 하는데 커밋 메시지를 내키는 대로 작성하게 되면 어떻게 될까요? 예를 들어, 아래의 사진을 봅시다.
위와 같이 커밋 커멘트를 작성했었다고 했을 때, 저 커밋이 어떠한 내용이 담긴 것인지 한눈에 파악할 수 있을까요? 아마 대부분의 사람들은 그렇지 않다고 느낄 것입니다. 위처럼 커멘트가 'AAAAAAA'라면 일일이 코드 변경사항을 클릭해서 확인해야 할 것입니다. 비단 이러한 사례뿐만 아니라도 다른 커멘트 역시 당장 어떤 내용인지 파악하기가 어렵습니다.
실제로 저도 개발에 무지하고 알고리즘 문제만 풀어서 깃허브에 올릴 때 위처럼 커밋을 날렸었습니다. 아래의 사진이 제가 임의로 작성한 커밋 커멘트입니다. 단순히 merged, update만 나와 있어서 뭘 merge한 것인지, 어떤 코드를 update한 것인지 파악이 안 됩니다.😅
이와 달리 최근에 커밋 컨벤션을 배우고 난 후 약간 달라진 다른 레포지토리의 커밋 히스토리를 보겠습니다.
위와 달리 그래도 내가 어떤 기능을 추가했는지, 어떤 테스트 코드를 작성했는지 조금 더 뚜렷히 파악할 수 있습니다. 처음에는 이렇게 작성하는 방법이 익숙지 않고 불편하게 느껴질 수도 있지만, 당장 다른 사람과 같이 프로젝트를 협업하여 진행할 때 다른 사람들이 우리의 커밋을 보고 빠르게 파악해서 프로젝트를 진행할 수 있을 것입니다. 그렇기 때문에 자연스레 생산성도 좋아지고요!
✅ 커밋 메시지 구조
기본적으로 커밋은 제목(Subject), 본문(Body), 꼬리말(Footer)로 나뉩니다. 그렇기에 실제로 보면 아래와 같은 구조를 갖습니다.
<타입>[스코프]: <제목>
# 공백
[바디]
# 공백
[꼬리말]
기본적으로 제목은 반드시 존재해야 하며, 그외 바디와 꼬리말 내용은 선택적으로 작성하면 됩니다. 먼저 제목에 대해서 알아보겠습니다.
1. 제목
제목은 타입와 제목으로 구성됩니다. 타입은 영어로 작성해주며 타입: 제목
으로 완성해줍니다. 반드시 : 뒤에 스페이스로 공백을 두어야 합니다.
1️⃣ 타입
타입은 해당 커밋이 어떠한 타입을 나타냅니다. 예를 들어, 해당 커밋이 특정 api 기능을 만든 것일 수도 있고, 테스트 코드를 작성한 커밋일 수도 있고, 버그를 고치거나, 리팩토링을 하는 등 다양한 종류의 커밋이 존재할 수 있습니다.
그렇기에 반드시 타입을 지정해주어서 해당 커밋이 어떠한 커밋인지 나타내주어야 합니다. 해당 타입들은 @commitlint/config-conventional 패키지의 공식문서에서 기재된 타입들입니다. 🙂
타입 | 설명 |
build | 빌드와 관련된 변경사항(e.g. npm related/의존성 추가) |
chore | 배포 환경에 대한 내용이 아닐 때의 커밋 - 빌드 수정, 패키지 매니저 수정 등(e.g. .gitignore 혹은 .prettierrc 변경 |
ci | CI 관련 설정 수정 |
feat | 새로운 기능 |
fix | 버그 수정 |
docs | 문서 변경 |
refactor | 코드 리팩터링 |
perf | 기능 개선 |
test | 테스트 코드 생성 혹은 수정 |
BREAKING CHANGE | API를 상당히 많이 바꾼 경우 |
💡BREAKING CHANGE는 꼬리말에 BREAKING CHANGE 타입을 가지는 커밋을 의미합니다. 혹은 타입과 스코프 사이에 !를 삽입하여 나타낼 수도 있습니다.
2️⃣ 스코프
스코프는 해당 커밋이 어떠한 곳에서 작성된 것인지 코드 베이스를 지정해주는 것입니다. 반드시 작성할 필요는 없으며, 조금 더 확실하게 커밋 메시지를 이해할 수 있도록 해줍니다. 예를 들어, middleware에서 변화가 발생했다면, feat(middleware)와 같이 작성할 수 있습니다.
스코프들은 아래와 같은 값으로 작성할 수 있습니다.
- init
- runner
- watcher
- config
- web-server
- proxy
- middleware
- etc.
3️⃣ 제목
제목은 최대한 쉽고 간결하게 작성해줍니다. 가장 대표적인 규칙은 아래와 같습니다.
- 제목은 동사원형으로 시작합니다.
- 제목은 50글자를 넘지 않도록 작성합니다.
- 마침표와 같은 특수 기호는 사용하지 않습니다.
- 첫 글자는 대문자로 작성합니다.
한글의 경우도 유사하며, 동사원형을 가장 전단에 기록합니다.
feat: Add login api
feat: 추가 login api
2. 바디(본문)
본문은 작성하고 싶지 않으면 굳이 작성할 필요는 없으나, 자세한 내용을 알리고 싶다면 사용하는 것도 좋은 방법입니다. 필수가 아니기 때문에 제목만큼 엄격하지는 않지만, 일정 규칙을 지키는 것이 좋습니다.
- 본문은 한 줄당 72자 이내로 작성합니다.
- 최대한 상세하게 작성합니다.
- 본문의 내용은 어떻게가 아니라 무엇과 왜에 집중해서 작성합니다(What, Why).
예를 들어 로그인 api를 만들었다고 가정한다면,
1. 로그인 기능 추가
- POST /users/login으로 요청
- 로그인 하지 않은 회원만 가입하도록 미들웨어 사용
위와 같이 작성하면 됩니다.
여러 줄의 메시지를 작성할 때는 '-' 혹은 번호를 사용해서 구분해줍니다.
3. 꼬리말(Footer)
꼬리말은 주로 이슈에 대한 내용을 위해 사용합니다. 꼬리말도 본문과 마찬가지로 반드시 작성해야 하는 요소가 아닌 선택사항이지만, 어느 정도 형식은 지켜야 합니다. 꼬리말의 형식은 유형: #이슈번호
와 같이 작성합니다.
규칙은 아래와 같이 정리할 수 있습니다.
- 유형과 이슈번호를 작성합니다.
- 여러 개의 이슈 번호를 적고 싶다면, 쉼표(,)를 사용해서 구분해줍니다.
꼬리말의 유형은 아래의 유형들 중에서 하나를 선택해 나타내줍니다.
유형 | 내용 |
Fixes | 이슈 수정중(해결되지 않음) |
Resolves | 이슈 해결 |
Ref | 참고 이슈 |
Related to | 해당 커밋과 관련된 이슈 |
꼬리말을 여러 개 사용할 수도 있습니다. 그래서 임의로 작성해보면 아래와 같이 작성할 수 있습니다.
Fixes: #1
Ref: #33
Related to: #16, 19
📍팁
추가적으로, 컨벤셔널 커밋 패키지를 통해서 커밋 리버트를 다룰 수도 잇습니다. 추천하는 방법은 revert타입을 사용하고, 꼬리말에 커밋의 아이디를 작성하는 것입니다.
revert: let us never again speak of the noodle incident
Refs: 676104e, a215868
✍🏻 정리하며
물론 내가 원하는대로 임의로 커밋 메시지를 작성할 수 있습니다. 하지만, 커밋 메시지를 컨벤션에 맞춰서 작성하면 사실 팀에게도 편리할 수 있지만, 나에게도 편리한 방법입니다. 갑자기 코드에 에러가 발생해서 롤백해야 할 때, 혹은 이전에 작성한 코드에서 인사이트를 얻어야 할 때 등 여러 경우에서 커밋 히스토리를 파악해야 하는 상황이 종종 발생합니다. 이럴 때 컨벤셔널 커밋이 빛을 발휘합니다.
다들 커밋 컨벤션을 지켜서 프로젝트 한 접시 어떠신가요?🍽