본문 바로가기
MJU Session (22-23)

[Session] 조금 더 편리한 협업을 도와줄, Git Hooks / 박소정

by sojungpp 2023. 3. 13.

작성자: 박소정


'아 커밋 메시지 잘못 입력했다..😑' Git을 활용해 팀 프로젝트를 진행할 때는, 가독성과 오류 발생을 줄이기 위해 개발 규칙을 정하곤 한다. 하지만, 사람인지라 누구든 종종 전략과 다른 커밋 메시지를 잘못 입력하는 등의 실수를 하기도 한다. Git에는 이러한 문제를 사전에 방지해 주고, 더 편리한 협업을 도와주는 기능이 있다. 이번 세션을 통해 그 기능인 Git Hooks를 알아보려 한다.

 

 

1. Git Hooks 알아보기

1-1. Git Hooks 개념

Git Hooks는 Git에서 어떤 이벤트가 발생했을 때, 원하는 작업을 특정 스크립트를 통해 실행할 수 있게 하는 기능이다.
Git Hooks 공식 문서

 

 

1-2. Git Hooks 종류

Git Hooks는 크게 클라이언트 훅, 서버 훅으로 나뉜다. 클라이언트 훅은 commit, merge 이벤트와 관련되어 이들이 발생하기 전에 클라이언트에서 실행하는 훅이며, 서버 훅은 git의 repository로 push가 발생했을 때 서버에서 실행하는 훅이다.

 

 

Client Git Hooks

분류 발생 시점
커밋 워크플로 훅 pre-commit commit 실행 전
prepare-commit-msg commit message 생성 후 편집기 실행 전
commit-msg commit message 완성 후 commit 최종 완료 전
post-commit commit 완료 후
이메일 워크플로 훅 applypatch-msg git am 명령 실행 후 가장 처음
pre-applypatch patch 적용 후 실행 (중단 가능)
post-applypatch git am 명령 실행 후 가장 마지막 (중단 불가)
기타 클라이언트 훅 pre-rebase rebase 전
post-rewrite git commit -amend, git rebase 등 커밋 변경 명령 실행 후
post-merge merge 완료 후
pre-push git push 실행 후 리모트로 데이터 전송 전 (중단 가능)

 

 

Server Git Hooks

분류 발생 시점
서버 훅 pre-receive push 실행 후 가장 처음
update push 실행 후 각 브랜치마다 한 번씩 실행
post-receive push 완료 후 실행

 

 

2.  Git Hooks 사용하기

2-1. Git Hooks 사용 방법

원하는 Git Hooks를 사용하기 위해서는 프로젝트의 .git/hooks 디렉토리 안에 설정하고자 하는 훅 이름으로 스크립트를 저장하면 된다.

만약, commit을 하기 전에 특정 메시지를 띄우고 싶다면 다음처럼 진행된다.

// 경로로 이동
$ cd .git/hooks/
 
// 훅이름 file 생성
$ touch pre-commit
 
// 훅 실행 시점에서 실행시킬 코드 작성
$ vi pre-commit
# pre-commit 파일

# 'Commit message: [MJU-이슈번호] 메시지' 를 출력시키기
echo 'Commit message: [MJU-이슈번호] 메시지'

# Exit 코드가 0이 아니면 커밋 취소
exit 0

 

 

2-2. Git Hooks 공유 방법

위처럼 만든 Git Hooks를 팀원과 공유하고자 할 때, 스크립트들은 모두 .git 파일 내에 있기 때문에 git에 파일이 올라가지 않는다.

해당 문제를 해결함과 동시에 Git Hooks 제어를 간편하게 해주기 위해서는 Husky를 사용하면 된다.

Husky 공식 문서

# Husky ver 6 기준

# husky 설치
npx husky-init && npm install

# package.json 설정
{
  "scripts": {
    ...
    "prepare": "husky install"
  },
}

# 훅 추가
npx husky add .husky/[hook] '[code]'

 

 

3.  Git Hooks 활용하기

3-1. Commit message 형식 검증

커밋 워크플로 훅

만약 commit message 규칙을 '[MJU-이슈번호] message' 의 형태로 정했다면, 이는 입력된 commit message가 원하는 정규식과 일치하는지 확인하여 push가 이루어지는 것을 관리하면 될 것이다. 따라서 이러한 경우에는 commit-msg 훅을 이용하면 된다.

$ cd .git/hooks/
$ touch commit-msg
$ vi commit-msg
# commit-msg 파일

# 원하는 정규식
$regex =  /^\[MJU-[0-9]+\][\d\D]*refs[\s]?-[\s]?.*/
 
def check_message_format

  # ARGV는 commit message가 들어 있는 임시 파일 경로
  message_file = ARGV[0]
  # 위의 경로에서 commit message를 받아온다
  message = File.read(message_file)
  
  if !$regex.match(message)
    puts "[POLICY] 잘못된 커밋 메시지 형식입니다."
    puts "[RULE] [MJU-{issueTicketNumber}] \n\n /* message */ \n\n refs - {issueLink}"
    exit 1
  end
end
check_message_format

 

 

3-2. Branch로부터 Issue 번호 가져와서 commit message 생성

Jira를 사용한다면, 대부분 branch와 commit message를 이슈 번호 관리를 통해 에러 발생 시 빠르게 대처할 수 있도록 다음과 같은 규칙을 사용한다.

Branch: feature/특정이름-이슈번호-어쩌구
예시: feature/MJU-231-post
Commit Message: 특정이름-이슈번호 커밋내용
예시: MJU-231 게시글 업로드 API 추가

이렇게 commit 할 때마다 작성해야 하는 message는 실수를 유발하기도 쉬우며, 무엇보다 귀찮은 일 중 하나이다. 
따라서, 이를 Git Hooks의 prepare-commit-msg 훅을 이용해 branch로부터 이슈 번호를 가져와 commit message에 자동으로 적용할 수 있다. 

$ cd .git/hooks/
$ touch prepare-commit-msg
$ vi prepare-commit-msg
#!/bin/bash

# 만약, branch가 master, develop, release, hotfix인 경우 스킵
if [ -z "$BRANCHES_TO_SKIP" ]; then
  BRANCHES_TO_SKIP=(master develop release hotfix)
fi

# 브랜치 이름에서 이슈 번호 가져오기
BRANCH_NAME=$(git symbolic-ref --short HEAD)
BRANCH_NAME="${BRANCH_NAME##*/}"
JIRA_ID=`echo $BRANCH_NAME | egrep -o 'HD.-[0-9]+'`

BRANCH_EXCLUDED=$(printf "%s\n" "${BRANCHES_TO_SKIP[@]}" | grep -c "^$BRANCH_NAME$")
BRANCH_IN_COMMIT=$(grep -c "$JIRA_ID" $1)

# 커밋 메시지에 이슈 번호가 적혀있는지 확인 후, 있다면 skip, 없다면 맨 앞에 이슈번호 추가
if [ -n $JIRA_ID ] && ! [[ $BRANCH_EXCLUDED -eq 1 ]] && ! [[ $BRANCH_IN_COMMIT -ge 1 ]]; then 
  sed -i.bak -e "1s/^/$JIRA_ID /" $1
fi​

 


여러 사람이 함께하는 프로젝트일수록 체계적인 개발 규칙은 서로의 코드를 보다 쉽게 알아보고, 에러 발생 시 빠르게 대처할 수 있기에 중요한 부분 중 하나라 생각한다. 하지만 솔직히 이는 꽤나 귀찮은 작업이고, 실수도 발생하기 쉽다는 문제가 있다. 그러나 이를 앞선 예시처럼 프로젝트 내에서 Git Hooks를 활용한다면, 보다 체계적인 개발에 도움이 될 것이라 생각한다.

 

 

 

 

[References]

Git hooks 이란?

Git Hook commit-msg 적용하기

Husky로 Git Hook 하자

GitHub 커밋 메시지에 JIRA 이슈번호 자동으로 넣어주기