
한 달여 만에 작성하게 됐습니다.
당시에 머릿속으로 그려놓은 초안이 있었는데 기억이 휘발돼서 다시 끄집어내느라 고생하고 있습니다..
오늘은 커밋 컨벤션에 대해 알아보려고 합니다.
간단하게 커밋 컨벤션은 프로젝트 참여자들이 일관된 형식의 커밋 메시지를 작성하기 위한 규칙을 말합니다.
커밋 컨벤션 예시는 링크를 참고하시기 바랍니다!
링크 확인하기
여기서 저는 커밋 컨벤션을 지키지 않고 커밋을 작성할 경우 커밋이 불가능하게 하기 위해서 패키지를 사용할 예정입니다.
물론, 패키지 없이 불가능한 것은 아닙니다.
Git Hooks를 사용하면 어떤 이벤트(commit, push 등)가 생겼을 때 자동으로 특정 스크립트 (코드 포맷 체크, 커밋 컨벤션 체크 등)를 실행하도록 할 수 있습니다.
여기까진 좋아보입니다.
다만, 이 스크립트 파일은 .git/hooks에 작성을 하는데, 이 때 .git 폴더 자체는 추적을 안하기 때문에 원격 레포지토리에 올라가지 않습니다. 따라서 스크립트 작성자가 코드를 복사하거나, 파일을 공유하는 등의 방법을 사용해된다는 번거로움이 생깁니다.
Git Hooks의 기능을 손쉽게 이용하면서 동시에 위에 언급한 번거로움을 해결하기 위해 사용할 패키지로는 husky, lefthook이 있는데 저는 플러터를 사용하므로 lefthook을 사용하도록 하겠습니다. (husky 관련 글은 많그든요)

재밌네.. 진행 시키지마
lefthook 설치를 했다는 가정 하에 글을 작성하겠습니다.
원하시면 설치법도 써드릴게요..
정말 간단하게 사용할 수 있습니다.
이벤트가 생겼을 때 트리거 되어야 할 스크립트 코드를 작성한 파일을 생성하고 lefthook.yml에서 이벤트와 실행할 파일을 작성해주면 됩니다.
이 글에선 commit-msg를 잘 작성했는지 확인해보려고 합니다.
이미지와 함께 보겠습니다!

프로젝트의 루트 경로에 git_hooks/commit_convention.dart를 생성했습니다.
이제 코드를 작성합니다.

import 'dart:io';
dynamic main() {
final rootDir = Directory.current;
final commitFile = File("${rootDir.path}/.git/COMMIT_EDITMSG");
final commitMessage = commitFile.readAsStringSync();
final regExp = RegExp(
'(teddy|juno|marco|judy), (Feat|Update|Fix|!BREAKING CHANGE|!HOTFIX|Style|Refactor|Comment|Chore|Docs|Test|Rename|Remove)::.*(#\\d+)',
);
final valid = regExp.hasMatch(commitMessage);
if (!valid) {
print('''👎 잘못된 커밋 메세지입니다!
아래 예제를 참고해주세요
------------------------------------------------------
" <작업자 이름>, <Prefix>:: 커밋 내용 #{issue number}"
" juno, Feat:: 구글 로그인 기능 추가 #123"
------------------------------------------------------
사용가능한 commit의 Prefix는 아래와 같습니다.
=============== 반드시 콜론을 두 개(::)를 사용하고 띄어쓰기 후 내용을 입력합니다. ===============
Feat:: 새로운 기능을 추가
Update:: 기능 수정
Fix:: 버그 수정
!BREAKING CHANGE:: 커다란 API 변경의 경우
!HOTFIX:: 급하게 치명적인 버그를 고쳐야하는 경우
Style:: CSS 및 UI, 코드 포맷 변경, 세미 콜론 누락, 코드 수정이 없는 경우
Refactor:: 코드 리팩토링 (기능 변경 X, 코드 가독성, 구조, 품질 개선의 경우)
Comment:: 필요한 주석 추가 및 변경
Chore:: 빌드 업무 수정, 패키지 매니저 수정
Docs:: 문서 수정
Test:: 빌드 업무 수정, 패키지 매니저 수정, 패키지 관리자 구성 등 업데이트, Production Code 변경 없음
Rename:: 파일 혹은 폴더명을 수정하거나 옮기는 작업만인 경우
Remove:: 파일을 삭제하는 작업만 수행한 경우
==================================================================================
''');
exitCode = 1;
} else {
print('''👍 나이스한 커밋 메세지입니다!''');
}
}
저는 "작업자의 이름, 작업 키워드:: 커밋 내용 #이슈 번호" 형태로 커밋 메세지를 작성할 수 있도록 스크립트를 작성했습니다.
이슈 번호는 저번 글에서 언급했습니다.

commit-msg:
commands:
validate:
run: flutter pub run ./git_hooks/commit_convention.dart
여기까지 됐다면 세팅이 끝났습니다.
세팅이 끝났으니 작업에 들어가기 전 issue를 등록하고 작업 후 커밋까지 해보겠습니다.

위와 같이 login 기능 구현 작업을 등록합니다.
로그인 기능을 끝냈다고 가정하고 커밋 컨벤션이 잘 적용됐는지 테스트를 해보겠습니다.

커밋 메세지를 대충 적었더니 위에 작성했던 스크립트가 터미널에 출력됩니다.

얄짤 없습니다.
설정한 컨벤션을 지켜 커밋 메세지를 작성하면 아래와 같이 출력됩니다.


이렇게 일관되게 커밋 메세지를 작성하면 깃허브 레포지토리에서도 깔끔하게 정리된 것을 볼 수 있습니다.
아래는 실제로 적용한 프로젝트의 레포지토리입니다.

아래 사진은 예전에 작성했던 커밋입니다.
위와 아래를 비교를 해보니 위가 더 나아보입니다.
위의 사진에서도 아쉬운 부분들이 보이긴 합니다. 이름이나 키워드 같은..

저번 글과 더불어 이번 글까지 따라해서 적용을 하셨다면
팀원과 협업 시 조금 더 효율적인 의사소통이 가능할 것으로 예상이 됩니다 😁
wow