기본 콘텐츠로 건너뛰기

[git] git hooks(훅)

git에서도 hook을 추가 할 수 있습니다.

프로그래밍에서 hook이란 특정 이벤트 또는 함수가 호출 되기 전,후에 호출이 되는 코드를 말합니다.

git에서의 이벤츠는 커밋, 풀, 머지 등과 같은 작업으로부터 특정 스크립트를 실행을 시킬 수 있습니다.
(해당 스크립트는 perl, python등과 같은 스크립트 언어로 작성이 가능 합니다.)
git은 크게 local과 remote두가지로 나눌 수 있늗데 hooks또란 이 두가지경우 모든 설정을 각각 해 줄 수 있습니다.

git과 연동된 프로젝트에서 .git이라는 디렉토리를 확인 할 수 있습니다.

$ ls -ahl . .. .git

해당 디렉토리는 숨긴상태로 뜨기 때문에 -ahl이라는 옵션을 추가 해 줍니다. 윈도우의 경우 디렉토리 옵션에 들어가서 숨긴 폴더표시를 눌러주시면 됩니다.

$ cd .git $ ls applypatch-msg.sample pre-push.sample commit-msg.sample pre-rebase.sample post-update.sample pre-receive.sample pre-applypatch.sample prepare-commit-msg.sample pre-commit.sample update.sample
.git/hooks 아래에 .sample로 이미 만들어진 hooks파일이 존재합니다.

해당 훅을 사용하기 위해서는 .sample을 지워주기만 하면 됩니다.


클라이언트 훅

1. 커밋 훅

commit훅은 pre-commit, prepare-commit-msg, commit-msg, post-commit 4가지가 존재합니다.

pre-commit : 커밋할 때 가장먼저 호출되는 훅입니다. 커밋 메시지를 작성하기 전에 호출이 됩니다. 이 훅에서  커밋하는 스냅샷을 검사를 합니다. 빠트린 것이 없는지, 테스트 유무를 점검을 하게 됩니다. 커밋할 때 꼭 확인할 게 있으면 pre-commit훅을 사용하여 확인을 하면 됩니다. 이 훅은 exit가 0이 아니면 커밋이 취소가 됩니다git commit --no-verify를 해주면 해당 pre-commit훅을 일시적으로 생략이 가능합니다.
추가적으로 lint같은 프로그램으로 코드 스타일을 검사하거나, 라인 끝 공백 문자를 검사하거나(.sample로 작성된 코드가 하는 행위입니다), 새로 추가한 코드에 주석이 달려있는지 검사를 할 땐 pre-commit훅을 이용하시면 됩니다.

 prepare-commit-msg : 이 훅은 깃이 커밋 메시지를 생성하고 나서 편집기를 실행하기 전에 실행됩니다. 이 훅은 사람이 커밋 메시지를 수정하기 전에 먼저 프로그램으로 손보고 싶을 때 사용한다. prepare-commit-msg는 인자를 받는데 커밋 메시지가 들어있는 파일 경로, 커밋의 종류 두개의 인자를 받게되는데, 최근 커밋을 수정할 때는(Amending 커밋) SHA-1 값을 추가적으로 더 받게 됩니다. prepare-commit-msg은 Merge 커밋, Squash 커밋, Amend커밋일 때 유용하다.

commit-msg : 이 훅은 커밋 메시지가 들어 있는 임시 파일의 경로를 인자로 받게됩니다. pre-commit과 마찬가지로 exit 0이 반환되지 않으면 커밋이 취소됩니다. 이 훅에서는 최종적으로 커밋이 완료되기 전에 프로젝트 상태나 커밋 메시지를 검증합니다. 커밋 메시지가 해당 프로젝트 정책에 맞는지 검사등을 수행을 하면 됩니다.

post-commit : 이 훅은 커밋이 완료되면 실행이 됩니다. 이 훅은 넘겨받는 인자가 하나도 없지만 커밋 해시정보는 git log -l HEAD 명령으로 쉽게 가져올 수 있습니다. 일반적으로 이 스크립트는 커밋된 것을 누군가 혹은 다른 프로그램에게 알릴 때 사용합니다.

2. 이메일 워크플로 훅
applypatch-msg, pre-applypatch-msg, post-applypatch 3가지가 있다. 해당 문서에서는 해당 명령(git format-patch)을 사용 할 일이 없으면 읽지 말라고 한다 ㅋㅋㅋㅋㅋ
그래도 최소한 무엇을 하는지만 알아가보도록 하겠습니다

applypatch-msg : 가장먼저 실행 되는 훅입니다. exit 0을 하지 않으면 patch를 하지 않습니다. 이 훅은 Author가 보내온 커밋 메시지 파일의 이름을 인자로 받게 됩니다. 커밋 메시지가 규칙에 맞는지 확인하거나 자동으로 메시지를 수정할 때 이 훅을 사용합니다.

pre-applypatch : git am으로 patch할 때 두번째로 실행되는 훅입니다. 이 훅은 인자를 받지 않고, 단순하게 Patch를 적용하고 나서 실행됩니다. 커밋이 스냅샷을 점검할 때 사용합니다. 0이 아닌 값을 반환시켜서 git am명령을 취소 할 수 있습니다.

post-applypatch: git am명령에서 마지막으로 실행 되는 훅입니다. patch를 보낸 사람이나 그룹에게 알림 메시지를 보낼 수 있습니다. 이 훅은 patch를 중단 시킬 수 없습니다.

3.기타 훅

pre-rebase: rebase하기 전에 실행 됩니다. 0아 아닌 값을 반환하면 rebase가 취소 됩니다. 이 훅으로 이미 push한 커밋을 rebase 하지 못하게 할수 있습니다. git이 자동으로 넣어주는 pre-rebase예제가 바로 이 예제입니다. 이 예제는 기준 브랜치가 next라고 되있습니다. 참고하여 실제로 적용할 브랜치 이름으로 사용하면 됩니다.

post-rewrite : 커밋을 변경하는 명령을 실행했을 때 실행하는 훅입니다. git commit --amend나 git rebase같은 명령이 post-rewrite 훅을 실행시키는 명령어에 해당됩니다. git filter-branch명령은 해당되지 않습니다. 훅의 용도는 post-checkout이나 post-merge훅과 비슷합니다.
디렉토리에서 뭔가 할 일이 있을 때 사용합니다. 예를들면 용량이 크거나 깃이 관리하지 않는 파일을 옮기거나 문서를 자동으로 생성하는데 사용하시면 됩니다.

post-merge : 머지가 끝이나면 실행이 됩니다. 이 훅은 파일 권한 길이가 깃이 추적하지 않는 정보를관리하는 데 사용합니다. 

post-push : git push 명령을 실행하면 동작하는데 리모트 정보를 업데이트 하고 난 후 리모트로 데이터를 전송하기 전에 동작합니다. 리모트의 이름과 주소를 인자로 받습니다. 0이 아닌 값을 반환하면 push를 중단시킬 수 있습니다.

서버 훅

클라이언트 훅으로도 어떠한 정책을 강요할 수 있지만 시스템을 관리하는 입장에서는 서버 훅이 더 중요합니다. 서버 훅은 모두 push 전후에 실행됩니다. push전에 실행되는 훅이 0이 아닌 값을 반환하면 해당 push는 거절이 됩니다.

pre-receive : push를 하면 가장 처음 실행되는 훅입니다. 해당 스크립트는 표준 입력(STDIN)으로 push하는 레퍼런스를 목록으로 입력받습니다. 0이 아닌 값을 반환하게 되면 해달 레퍼런스를 모두 거절합니다. Fast-forward Push가 아니면 거절하거나, 프랜치 권한 Push 권한을 제어하려면 이 훅에서 하는 것이 좋습니다. 

update : update는 스크립트는 각 브랜치마다 한 번씩 실행된다는 것을 제외하면 pre-receive와 거의 같습니다. 한 번에 브랜치를 여러 개 push하면 pre-receive를 딱 한번만실행되니만, update는 브랜치마다 실행이됩니다. 이 스크립트는 인자를 표준 입력으로 데이터를 받지 않습니다.

post-receive :  push한 후에 실행됩니다. 이 스크립트가 종료할 때까지 클라이언트와의 연결은 유지되고 push를 중단시킬 수 없다. 그래서 이 스크립트로 시간이 오래 걸릴만한 일을 할 때는 조심해야 합니다.




그럼 해당 훅을 수정하여 정상동작을 하는지 확인을 해보도록 하겠습니다.

pre-commit.sample을 pre-commit으로 이름을 변경을 합니다. 해당 파일을 열어서 아래와 같이 수정을 해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments.  The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
echo 'hello world'
if git rev-parse --verify HEAD >/dev/null 2>&1
then
        against=HEAD
else
        # Initial commit: diff against an empty tree object
        against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
        # Note that the use of brackets around a tr range is ok here, (it's
        # even required, for portability to Solaris 10's /usr/bin/tr), since
        # the square bracket bytes happen to fall in the designated range.
        test $(git diff --cached --name-only --diff-filter=-z $against |
          LC_ALL=C tr -'[ -~]\0' | wc -c) != 0
then
        cat <<\EOF
Error: Attempt to add a non-ASCII file name.
This can cause problems if you want to work with people on other platforms.
To be portable it is advisable to rename the file.
If you know what you are doing you can disable this check using:
  git config hooks.allownonascii true
EOF
        exit 1
fi
# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --
cs

중간에 echo 'hello world'를 추가를 해보았습니다.

$ git commit -m 'test' hello world [master j1j2h3] test ...중략... 1 file changed, 2 insertions(+), 1 deletion(-)
 와 같이 정상적으로 훅이 실행됨을 확인 할 수 있습니다.


댓글

이 블로그의 인기 게시물

[db] mac에서 mysql환경설정 셋팅하기 1편 - 설치 및 접속, ERROR 2002 (HY000) : Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) 해결방법

mac에서 mysql을 환경설정하는 방법에 대해서 다뤄보도록 하겠습니다. 그동안 aws에서 제공하는 rds를 사용했기 때문에 로컬 디비를 거의 안썼는데 테스트 하고 싶은것이 있어 로컬에 디비설치를 하려고 했더니 몇몇 문제가 발생하여 공유하기 위해 정리를 해봅니다. 크게 설치 및 접속, 보안 및 chatset에 대해서 알아보겠습니다. 우선 아래의 설명은 homebrew가 설치가 되어있어 brew를 사용할 수 있다는 가정하에 설명을 진행을 하도록 하겠습니다. $ brew install mysql brew를 이용하여 mysql을 설치를 해줍니다. 리눅스 같은 경우는 mysql-server를 설치를 하는데 mac에서는 mysql을 설치를 하네요 $ mysql -u root -p Enter password: ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) 접속을 시도해 보았더니 로컬 서버에 접속을 할 수 없다고 뜹니다. 에러발생 원인: 디비서버 열려있지 않음. 해결방법: 디비서버 실행 디비를 설치를 했지만 실행을 하지 않았기 때문에 위와같은 에러가 발생을 하게 됩니다. 만약 linux사용자라면 service를 이용하여 서버를 실행시키겠지만 맥에서는 service를 지원을 하지 않는것 같아 다른 방법으로 시도를 해보았습니다. $ mysql.server start Starting MySQL . SUCCESS! mysql.server 명령어를 실행을 시켜주게 되면 /usr/local/bin/mysql.server 가 실행이 됩니다.

[git] git log 확인하기

git log를 통해서 커밋 이력과 해당 커밋에서 어떤 작업이 있었는지에 대해 조회를 할 수 있다. 우선 git에서의 주요 명령어부터 알아보겠다. $ git push [branch name] $ git pull [branch name] 여기서 branch name은 로컬일 경우 해당 브런치 이름만 적으면 되지만 깃허브 원격 저장소로 연결을 원할 경우는 해당 브런치 이름 앞에 꼭 origin을 붙이도록 한다. $ git brnch [branch name] $ git checkout [branch name] branch일경우 해당 브런치를 생성을 한다. 여기서 현재의 브런치를 기준으로 브런치를 따는것이다. checkout은 브런치를 바꾸는 것이다.(HEAD~[숫자]를 이용하면 해당 커밋으로 움직일수 있다.. 아니면 해당 커밋 번호를 통해 직접 옮기는것도 가능하다.) -> 해당 커밋으로 옮기는 것일뿐 실질적으로 바뀌는 것은 없다. 해당 커밋으로 완전히 되돌리려면 reset이라는 명령어를 써야한다. 처음 checkout을 쓰면 매우 신기하게 느껴진다. 막 폴더가 생겼다가 지워졌다가 ㅋㅋㅋㅋㅋ  master 브런치에서는 ht.html파일이 존재하지만 a브런치에서는 존재하지않는다. checkout 으로 변경을 하면 D 로 명시를 해준다.  $ git log 해당 브런치의 커밋 내역을 보여준다. a 브런치의 커밋 내역들이다. (머지 테스트를 하느라 커밋 내용이 거의 비슷하다 ㅋㅋ) master 브런치의 커밋 내역들이다. 커밋 번호, 사용자, 날짜, 내용순으로 등장을 한다. 이건 단순히 지금까지의 내역을 훑어보기 좋다. 좀더 세밀한 내용을 봐보자. $ git log --stat --stat을 붙이면 기존의 로그에서 간략하게 어떤 파일에서

[git] pull을 하여 최신코드를 내려받자

보면 먼가 로고가 다르게 뜨는것을 확인을 할 수가있다. C:\Users\mung\Desktop\etc\study\python-gene>git checkout remotes/origin/master Note: checking out 'remotes/origin/master'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example:   git checkout -b HEAD is now at 29e282a... fetch test C:\Users\mung\Desktop\etc\study\python-gene>git branch * (HEAD detached at origin/master)   master   test1   test2 깃이 잘 쓰면 참 좋은놈인데 어지간히 쓰기가 까다롭다. 처음에 깃을 푸시 성공하는데만 한달정도 걸렸던걸로 기억이 난다.. ㅋㅋㅋ 여담으로  깃 프로필을 가면 아래사진 처럼 보인다. 기여도에 따라서 초록색으로 작은 박스가 채워지는데 저걸 잔디라고 표현을 한다고 합니다 ㅎ 저 사진은 제 깃 기여도 사진입니당 ㅋㅋㅋㅋ 다시 본론으로 돌아와서 ㅋㅋ pull을 하면 깃에 최신 소