코드스테이츠에서 처음으로 진행하는 개인 프로젝트 쇼핑몰과 비슷하지만 매우 간단한 기능만을 가지고 있는 프로젝트인 fe-sprint-coz-shopping 를 일주일간 진행하였다.
이번 프로젝트에 git flow를 적용하기로 하여 다른 분들께 git flow에 대해 설명할 겸 간단히 흐름을 그려보았다.
feature에서 작업이 끝나면 PR을 올려 origin/develop 에 머지하고,
develop 브랜치에 체크아웃하여 origin/develop의 변경사항을 pull 하는 과정이다.
어느 날 한 분이 하나의 질문을 해주셨는데 "실수로 origin/main에 merge 했는데 어떡하죠?" 였다.
실제로 나도 전 프로젝트에 git flow를 적용하여 작업을 하다가 실수로 origin/main 브랜치에 머지한 적이 있었다.
물론 개인 프로젝트에서는 바로 revert하고 진행하면 큰 문제가 되지 않지만,
git hook은 Git 이벤트가 발생했을 때 특정 스크립트를 실행하는 것을 의미하며, husky는 git hook을 쉽게 사용할 수 있도록 도와주는 라이브러리이다.
git 이벤트와 git hook의 단계는 다음과 같다.
npx husky-init && npm install
prepare 스크립트는 패키지가 패킹 되기 전에 실행되는 스크립트로 npm publish, npm pack 의 스크립트가 실행될 때, 로컬에서 파라이터 없이 npm install 스크립트가 실행될 때 호출됩니다.
"scripts": {
...
"prepare": "husky install",
}
이번 프로젝트는 vite로 세팅하였고, vite의 기본 세팅에 eslint 검사를 위한 스크립트가 이미 추가 되어 있었다.
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
커밋하기 전 npm run lint
을 해서 문제가 없을 경우에만 커밋하고 싶기 때문에 npm run lint
를 뒤에 붙여 pre-commit hook을 추가해주었다.
npx husky add .husky/pre-commit 'npm run lint'
그러면 .husky/pre-commit 경로의 파일에 다음과 같은 내용이 담기게된다.
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint
그리고 이후 커밋마다 lint 검사를 하고 에러가 없을 경우에만 커밋을할 수 있도록 한다.
현재 m2 air 에서 nvm과 sourcetree를 사용하고 있었다.
sourcetree에서 테스트 커밋을 하려던 중 npm: command not found
에러와 만났다.
누군가 자세한 이유를 작성해주셔서 이 글을 통해 이유를 대충 알 수 있었다.
Sourcetree(osx)에서 Husky(git-commit-hook)가 동작하지 않는 이유: Can’t find “…” in PATH
요약하면 경로 문제였다.
공식 문서에서도 Troubleshooting의 첫 문제로 command not found를 정리하였다. Command not found 해결방법
stree
Husky 사용할 때 주의! v5 버전 릴리스와 라이선스 정책 변경
husky에 대해 찾아보다 위와 같은 글을 읽었는데 현재는 MIT 라이선스를 가진 상황이어서 v5를 제외한 버전은 걱정할 필요가 없다고 했다.
하지만 이 글을 통해 라이브러리 사용 전 라이선스를 꼭 확인해야겠다는 생각을 하게되었다.
pre-commit 에 적용하고 싶었던 내용은 다음과 같다.
따라서 위 세팅을 통해 만들어진 파일 아래 현재 체크아웃된 브랜치와 커밋하면 안되는 브랜치를 비교하여 일치할 경우 에러를 내는 코드를 추가하였다.
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint
# 현재 체크아웃된 브랜치
BRANCH=`git rev-parse --abbrev-ref HEAD`
# 커밋하면 안되는 브랜치
PROTECTED_BRANCHES="^(master|main|develop)"
echo "current branch: $BRANCH"
echo "protected branches: $PROTECTED_BRANCHES"
# 문자열을 비교하기 위한 문법
if [[ "$BRANCH" =~ $PROTECTED_BRANCHES ]]
then
echo -e "main 또는 develop에 commit할 수 없습니다."
echo -e "\n🚫 Cannot commit to local $BRANCH branch" && exit 1
fi
exit 0
pre-push에서 적용하고 싶은 내용은 다음과 같았다.
아래 주석으로 적었지만 BRANCH에서 BRANCH로 푸시할 때만 LOCAL_REF, REMOTE_REF 변수의 값을 알 수 있었다.
즉, feature/13에 체크아웃되어 있는 상태에서 develop 브랜치를 push하려고 한다면 LOCAL_REF, REMOTE_REF 정보가 뜨지 않았고
feature/13에 체크아웃되어 있는 상태에서 feature/13에 push할 때만 LOCAL_REF, REMOTE_REF 정보가 떴다.
따라서 "체크아웃된 브랜치에서 해당 브랜치만 Push하는지 확인하는 조건문"을 추가하여 체크아웃된 브랜치 외의 브랜치를 push하는 것을 막았으나 이는 그리 좋은 코드는 아닌 것 같다.
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# 출처: https://typicode.github.io/husky/migrating-from-v4.html
# 출처: https://library.gabia.com/contents/8492/
# 출처: https://stackoverflow.com/a/63322891
# 출처: https://github.com/typicode/husky/issues/1052
LOCAL_REF=""
REMOTE_REF=""
# 체크아웃된 브랜치에서 체크아웃된 브랜치만 push할 때 변수를 감지함
if read local_ref local_oid remote_ref remote_oid; then
echo "local_ref $local_ref"
LOCAL_REF="$local_ref"
echo "remote_ref $remote_ref"
REMOTE_REF="$remote_ref"
fi
# 체크아웃된 브랜치
BRANCH=`git rev-parse --abbrev-ref HEAD`
# push하면 안되는 브랜치
PROTECTED_BRANCHES="^(main|master|develop)"
# 문자열을 비교하기 위한 문법
if [[ "$BRANCH" =~ $PROTECTED_BRANCHES ]]
then
echo -e "main 또는 develop에 push할 수 없습니다. feature 브랜치로부터 PR을 만들어 제출해주세요."
echo -e "\n🚫 Cannot push to remote $BRANCH branch, please create your own branch and use PR." && exit 1
fi
echo "current branch: $BRANCH"
echo "protected branches: $PROTECTED_BRANCHES"
echo "remote name: $1"
echo "git url: $2"
# 체크아웃된 브랜치에서 해당 브랜치만 Push하는지 확인하는 조건문
if [[ $LOCAL_REF != *"$BRANCH"* ]]
then
echo -e "체크아웃한 브랜치만 push해주세요."
echo -e "\n🚫 You must use (git push origin $BRANCH)" && exit 1
fi
exit 0
글 잘 봤습니다, 많은 도움이 되었습니다.