Git Hook 이라는 것도 처음 들어보는데, Husky는 왜 또 쓰는 걸까?
어제 ESLint 관련 학습을 마치고 나서 Husky와 관련된 학습을 추가적으로 진행하려는데, Git hooks 이 무엇인지 묻는 질문에서 이미 내 정신은 턱 막혀버렸다. 도대체가 이놈의 공부는 하나를 좀 하려 하면 연쇄적으로 모르는 게 어디서 터져나온다. 아주 사람을 환장하게 만드는데는 도가 텄다.
결국 울며 겨자먹기로, 어차피 알아야 했을 내용이라 생각하며 Git hook에 대한 내용부터 먼저 학습했는데.. 어랍쇼 이거 봐라. 생각보다 유용하다. 따라서 오늘은 5시간 동안 여러 삽질과 정리를 통해 내가 어떻게 Husky를 적용하였고 자체적인 Git Hooks Script는 어떤 방식으로 작성했는지, 그리고 근본적으로 왜 Husky를 사용해야 하는지에 대한 고찰과 답변을 작성하고자 한다.
git am
명령어를 통해 patch 파일을 git에 반영할 경우 실행됨.git am
명령어 실행 시 가장 먼저 실행됨,git commit -amend
, git rebase
처럼 commit을 변경하는 명령을 실행한 후 실행.git push
명령 실행 시 작동하며, remote 정보를 업데이트 한 후 데이터를 전송하기 전 실행, push 중단 가능.git patch란?
git format-patch
명령어를 사용할 시, 적용된 각각의 commit에 대응되는 patch 파일이 생성된다.git am [patch-file]
명령어를 사용하여 commit에 반영시킨다.git rebase란?
Shell Script란?
#!/bin/bash
에서 #!
은 Shebang이라고 칭하며, 해당 Shell Script 파일을 해석해줄 인터프리터의 절대 경로를 지정한 것이다.#!/bin/bash
의 의미는 해당 파일을 여러 종류의 shell 중 bash
를 통해 실행시키겠다는 의미이다. sh
를 적용하고 싶다면 #!/bin/sh
를 작성하면 된다..git/hooks
디렉토리 안에 저장된다. 예시로 pre-commit
훅을 적용하여 commit 전에 Hello Gwangin!
메세지를 출력시키고 싶다면 아래와 같이 파일을 생성한다.
#!/bin/sh
echo 'Hello Gwangin!'
exit 0 # exit이 0이 아닐 경우 commit이 취소된다고 함.
pre-push
훅을 적용하여 직접적으로 master branch에 push 를 진행하는 것을 막고자 한다면, 아래와 같이 파일을 생성한다.
#!/bin/sh
PROHIBITED_REF="refs/heads/master"
if read local_ref local_sha remote_ref remote_sha
then
if [ "$remote_ref" = "$PROHIBITED_REF" ]
then
echo "prevent to push master"
exit 1
fi
fi
exit 0
./git/hooks
디렉토리에 스크립트를 넣을 경우 git에 올라가지 않는다..husky
폴더 내에 스크립트를 저장하면 git hook을 다른 개발자와 공유할 수 있다../git
이 존재하는 디렉토리에 ./husky
파일이 있어야 정상적으로 작동이 가능하다../git
디렉토리는 기본적으로 git ignore 대상이다, 따라서 hook을 공유하기 위해서는 별도의 작업이 필요하다.git_hooks
폴더를 만들고, 해당 폴더 내에 사전에 작성한 hook script 파일을 넣어둔다..git/hooks
폴더에 넣으면 된다.#!/bin/bash
cp git_hooks/* .git/hooks
git clone
시 --template
옵션을 통해 .git
디렉토리를 사전에 지정한 양식대로 초기화할 수 있다.git_template
폴더를 만들고, 실제 .git
폴더 구조처럼 hooks
폴더를 생성한 후 내부에 스크립트 파일을 추가한다./main/git_templates
└─ /hooks
└─ pre-push
└─ pre-commit
└─ etc...
--template
옵션에 사전에 생성한 template 디렉토리를 경로로 지정한다..git
디렉토리를 초기화한다. git clone --template=/main/git_templates https://github.com/RookieAND/test-git-hooks.git
단, 1번과 2번의 경우 결국 다른 사용자가 git hooks을 수동으로 적용해야만 한다.
고로 다른 사용자가 이를 까먹었을 경우 hook이 정상적으로 적용되지 않을 가능성이 높다.
따라서 이러한 문제를 해결하기 위해 도입된 library가 바로 husky 다.
npm
을 사용한다면, 하단의 명령어 한 줄로 기초 세팅이 완료된다.
npx husky-init && npm install
yarn
의 경우, 두 번에 걸쳐 세팅을 완료한다.
yarn add husky --dev
yarn husky install
설정이 완료되면 프로젝트에 .husky
디렉토리가 생성되고, 이 안에서 hook 스크립트를 추가하면 된다.
/.husky
└─ .gitignore
└─ husky.sh
└─ 내가 추가할 script...
lint-staged
라이브러리를 개별 의존성으로 설치해야 한다..lintstagedrc
파일을 생성하고 다음과 같이 코드를 적는다. (glob pattern)// js, jsx, ts, tsx 파일에 대한 eslint 검사 실행.
{
"./src/**/*.[jt]s?(x)": "eslint --cache --fix"
}
./husky
내에 pre-commit 훅 스크립트를 추가하고, 하단과 같이 내용을 작성한다./.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
commitlint.config.js
파일을 생성하고 다음과 같이 코드를 적는다.module.exports = { extends: ['@commitlint/config-conventional'] };
./husky
내에 commit-msg 훅 스크립트를 추가하고, 하단과 같이 내용을 작성한다.-edit
옵션을 사용하고, yarn의 경우 --edit
옵션을 사용하여 작성하면 된다./.husky/commit-msg
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit
fix 과 콜론 사이에 공백을 넣어서 빠꾸 당한 모습이다.