Git 은 Hook 이라는 기능을 가지고 있다.
Git Hook?
Git 과 관련한 어떤 이벤트가 발생했을 때 특정 스크립트를 실행할 수 있도록 하는 기능이다. 크게 클라이언트 훅 과 서버 훅 으로 나뉘는데 클라이언트 훅 은 커밋, Merge 가 발생하거나 push 가 발생하기 전 클라이언트에서 실행하는 훅이다. 반면 서버 훅 은 Git repository 로 push 가 발생했을 때 서버에서 실행하는 훅이다.
한마디로, Git에서 add
, commit
, push
와 같은 특정 이벤트를 실행할 때, 그 이벤트에 Hook을 설정하여 Hook에 설정된 스크립트를 실행할 수 있다.
Git에 특정 이벤트가 일어나 코드가 merge 되기 전에 자동으로 ESLint 와 Prettier 가 작동하여 규칙에 어긋난 코드 발견 시 원격 저장소에 저장되지 않도록 하기 위함이다.
.git
> hooks
폴더 내부를 보면 많은 git hook 관련 파일들이 존재한다.
뒤에 .sample 을 제거하고 본인이 원하는 대로 스크립트를 작성하면 실제로 hook이 동작한다.
하지만, Git을 통해 원격 저장소 혹은 다른 사용자가 공유할 수 없다는 문제점이 존재한다.
이를 위해 husky 사용한다.
먼저, 하기 명령어로 설치한다.
$ yarn add husky -D
다음 명령어를 통해 husky를 프로젝트 내에 설치한다.
$ yarn husky install
위 명령어를 실행했다면 root에 .husky
폴더 생성된 것을 볼 수 있다.
참고로 이 폴더는 각자 로컬에서 관리되므로 다른 동료 개발자들을 위해 package.json
에 script를 추가 해놓자.
"scripts": {
...
"husky": "husky install"
...
}
추가 설정은 lint-staged 와 함께 설명하겠다.
Commit Workflow Hooks 을 통하면 commit
이벤트 전/후로 hook을 동작시킬 수 있다.
종류는 다음과 같다.
pre-commit
: 커밋 시 가장 먼저 실행prepare-commit-msg
: Git이 커밋 메시지를 생성하고 편집기를 실행하기 직전에 실행commit-msg
: 커밋이 발생하기 직전에 실행post-commit
: 커밋이 발생한 직후에 실행이 중 pre-commit
훅을 통하면 커밋 이벤트 발생 시 먼저 특정 테스트를 강제하고, 테스트 실패 시 해당 커밋 이벤트를 취소시키는 것이 가능하여 가장 많이 사용 된다.
lint-staged 란, Git에 staging
한 파일들에 한하여 ESlint 및 Prettier와 같은 설정을 명령어를 통해 실행해주는 라이브러리다.
husky 만 사용하면 프로젝트의 모든 코드를 검사하기 때문에 비효율적이다.
즉, Git의 staging
된 코드만 검사하기 위해서 lint-staged 라이브러리가 필요하다.
하기 명령어를 통해 설치하자.
$ yarn add lint-staged -D
보통 package.json
파일 내 "lint-staged"
Key를 따로 분류하여 staging
영역에 적용시킬 기능을 추가한다.
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx}": [
"eslint --ext .tsx --ext .ts src/",
"prettier --write"
]
}
위 명령어는 project 내 모든 .js
, .jsx
, .ts
, .tsx
파일에 대해 ESLint와 Prettier를 검사하겠다는 명령어를 스크립트로 작성한 것이다.
다음 명령어를 통해 pre-commit
을 생성한다.
$ npx husky add .husky/pre-commit "yarn lint-staged"
참고로 yarn
으로는 생성이 안되고 npx
만 실행된다. (뭔가 명령어가 조금 다른 것 같다..)
생성 된 pre-commit
파일을 열어보면 다음과 같이 작성되어 있다.
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo "Hello, husky is running!"
yarn lint-staged
echo "OK. done."
필자는 스크립트가 실행되었다는 것을 알아보기 위해 명령어 사이에 echo
를 임의로 넣었다.