본문 바로가기
프로그래밍 놀이터/Tips

[도서 정리] 8. Git 맞춤 - ProGit

by 돼지왕 왕돼지 2020. 1. 13.
반응형

[도서 정리] 8. Git 맞춤 - ProGit



8.1.  GIt 설정하기


-

git 은 내장된 기본 규칙을 따르지만 설정된 것이 있으면 그에 따른다.


git 은 먼저 /etc/gitconfig 파일을 찾는다.

이 파일은 시스템에 있는 모든 사용자와 모든 저장소에 적용되는 설정 파일이다.

git config —system 을 이용하면 이 파일을 사용한다.


다음으로 ~/.gitconfig 파일을 찾는다.

이 파일은 해당 사용자에게만 적용되는 설정파일이다.

—global 옵션을 주면 git 은 이 파일을 사용한다.


마지막으로 현재 작업중인 저장소의 git 디렉터리에 있는 .git/config 파일을 찾는다.

이 파일은 해당 저장소에만 적용된다.



-

각 설정 파일에 중복된 설정이 있으면 순서대로 덮어쓴다.

즉 .git/config 의 설정값이 우선순위가 가장 높다.




* 클라이언트 설정


-

설정이 영향을 미치는 대상에 따라 클라 설정과 서버 설정으로 나눠볼 수 있다.

대부분은 클라 설정이다.


man git-config 로 설정 가능한 내용들을 볼 수 있다.



-

core.editor 는 git 의 편집기를 설정한다.

$VISUAL, $EDITOR 로 설정된 것이 없으면 vi 를 실행한다.


커밋할 때나 tag 메시지를 편집할 때 설정한 편집기를 실행한다.



-

commit.template 은 커밋 메시지의 템플릿을 설정하는 것이다.

$ git config —global commit.template file_name

$ git commit



-

core.pager 는 log, diff 같은 명령의 메시지를 출력할 때 paging 하는 규칙을 설정한다.

기본적으로 less 를 사용하는데, more 를 좋아하면 more 라고 설정한다.

페이지를 나누고 싶지 않으면 빈 문자열로 설정한다.



-

user.signkey 는 내 작업에 서명할 때 사용하다.

gpg 키를 설정하는 것이다.

$ git config —global user.signkey gpg_key_id

$ git tag -s tag_name



-

core.excludesfile 은 global level 로 gitignore 를 설정할 수 있다.

$ git config —global core.excludesfile <ignore_file_name>



-

help.autocorrect 는 명령어를 잘못 입력했을 때 git 이 자동으로 해당 명령어로 대체하여 명령을 수행한다.

$ git config —global help.autocorrect 1




* 컬러 터미널


-

git 은 기본적으로 터미널에 출력하는 결과물을 알아서 색칠한다.

하지만 이 기능을 끄고싶다면 color.ui 를 false 로 두면 된다.



-

좀 더 꼼꼼하게 컬러를 설정하려면 color.branch, diff, interactive, status 등에 true, false, always 를 설정할 수 있다.

$ git config —global color.diff.meta “blue black bold”




* 다른 merge, diff 도구 사용하기


-

P4Merge 가 추천되는 무료 툴 중 하나이다.

$ git config —global merge.tool extMerge

$ git config —global mergetool.extMerge.cmd ‘extMerge \”$BASE\” \”$LOCAL\” \”$REMOTE\” \”$MERGED\”'

$ git config —global mergetool.extMerge.trustExitCode false

$ git config —global diff.external extDiff




* Formatting and Whitespace


-

윈도우에서 개발하는 동료와 함께 일하면 new line 에 문제가 생길 수 있다.

윈도우는 CR, LF 문자를 둘 다 사용하지만, 맥과 리눅스는 LN 만 사용하기 때문이다.

git 은 커밋할 때 자동으로 crlf 를 lf 로 변환해주고 반대로 checkout 할 때 lf 를 crlf 로 변환해주는 기능이 있다.

core.autocrlf 를 이용하면 된다. true 로 하면 윈도우에서 checkout 할 때 lf 가 crlf 로 변환된다.

core.autocrlf 를 input 으로 설정하면 커밋할 때만 crlf 를 lf 로 변환한다.



-

git 에는 공백 문자를 다루는 방법으로 네 가지가 정의돼 있다.

blank-at-eol 은 각 라인 끝에 공백이 있는지 찾고, blank-at-eof 는 파일 끝에 추가한 빈 라인이 있는지 찾는다.

space-before-tab 은 모든 라인에서 처음에 tab 보다 공백이 먼저 나오는지 찾는다.

이들은 기본으로 켜져 있다.


indent-with-non-tab 는 tab 이 아니라 공백으로 시작하는 라인이 있는지 찾고,

cr-at-eol 은 라인 끝에 cr 문자가 있어도 괜찮다고 git 에 알리는 것이다.

이들은 기본적으로 꺼져있다.


core.whitespace 옵션으로 이 네가지 방법을 켜고 끌 수 있다.


ex) 

$ git config —global core.whitespace trailing-space, space-before-tab, indent-with-non-tab




* 서버 설정


-

git 은 push 할 때마다 각 객체가 sha-1 체크섬에 맞는지 잘못된 개체가 가리키고 있는지 검사하게 할 수 있다.

기본적으로 이 기능이 동작하지 않게 설정되어 있는데 개체를 점검하는데 시간이 걸리기 때문에 push 시간이 늘어나기 때문이다.

얼마나 늘어나는지는 저장소 크기와 push 양에 따라 다르다.


receive.fsckObjects 를 true 로 하면 push 할 때마다 검증한다.



-

이미 push 한 커밋을 rebase 해서 다시 push 하지 못하게 할 수 있다.

브랜치를 push 할 때 해당 리모트 브랜치가 가리키는 커밋이 push 하려는 브랜치를 없을때 push 하지 못하게 할 수 있다.

보통 이런 정책이 좋고 git push 명령에 -f 옵션을 주면 강제로 push 할 수 있다.


receive.denyNonFastForwards 옵션을 켜면 fast-forward 로 push 할 수 없는 브랜치는 아예 push 하지 않는다.



-

receive.denyDeletes 는 브랜치를 삭제하는 push 가 거절된다.

브랜치나 tag 를 삭제하는 push 는 거절된다.

아무도 삭제할 수 없다.

리모트 브랜치를 삭제하려면 직접 손으로 server 의 ref 파일을 삭제해야 한다.







8.2. Git Attributes


-

디렉터리와 파일 단위로 다른 설정을 할 수 있다.

경로별로 설정하는 것을 git attribute 라고 부른다.

이 설정은 .gitattributes 라는 파일에 저장하고 아무 디렉터리에나 둘 수 있지만, 보통은 프로젝트 최상위 디렉터리에 둔다.

이 파일을 커밋하고 싶지 않으면 .gitattributes 가 아니라 .git/info/attributes 로 파일을 만든다.



-

attribute 로 머지는 어떻게 할지, 텍스트가 아닌 파일은 어떻게 diff 할지, checkin/cehckout 할 때 어떻게 필터링할지 정해줄 수 있다.




* 바이너리 파일


-

이 attribute 로 어떤 파일이 바이너리 파일인지 git 에 알려줄 수 있다.

기본적으로 git 은 어떤 파일이 바이너리인지 알지 못한다.


attribute 파일에 패턴으로 명시해주면 된다.


ex)

*.pbxproj binary


이렇게 하면 CRLF 변환이 적용되지 않고, git show 나 git diff 같은 명령을 실행할 때에도 diff 를 출력하지 않는다.



-

git은 바이너리 파일도 diff 할 수 있다.

git attribute 를 통해 바이너리 파일을 텍스트 포맷으로 변환하고 그 결과를 diff 명령으로 비교하도록 하는 것이다.

예를 들어 word 문서를 비교할 때 사용할 수 있다.


ex)

*.docx diff=word


이렇게 하면 docs 파일의 diff 시 word 필터를 사용하라고 설정하는 것이다.

word 필터도 정의해줘야 한다.

word 문서에서 사람이 읽을 수 있는 텍스트를 추출해주는 docx2txt 를 사용하여 diff 에 이용하면 된다.


ex) 

$ git config diff.word.textconv docx2txt




* 키워드 치환


-

git 은 체크섬을 계산하고 커밋하기 때문에 그 커밋에 대한 정보를 가지고 파일을 수정할 수 없다.

하지만  checkout 할 때 그 정보가 자동으로 파일에 삽입되도록 했다가 다시 커밋할 때 삭제되도록 할 수 있다.

파일 안에 $ID$ 필드를 넣으면 blob 의 sha-1 체크섬을 자동으로 삽입한다.

이 필드를 파일에 넣으면 git 은 앞으로 checkout 할 때 해당 blob 의 sha-1 값으로 교체한다.

교체되는 체크섬은 커밋의 것이 아니라 blob 그 자체의  sha-1 체크섬이다.



-

commit/checkout 할 때 사용하는 필터를 직접 만들어 쓸 수 있다.

방향에 따라 clean 필터와 smudge 필터라 부른다.

checkout 할 때 파일을 처리하는 것을 smudge 필터이고, 커밋할 때 처리하는 필터가 clean 필터이다.

.gitattributes 파일에 설정하고 파일 경로마다 다른 필터를 설정할 수 있다.



-

이하 생략....




* 저장소 익스포트하기


-

프로젝트를 익스포트해서 아카이브를 만들 때도 git attribute 가 유용하다.

아카이브를 만들 때 제외할 파일이나 디렉터리를 설정할 수 있다.

특정 디렉터리나 파일을 프로젝트에는 포함하고 아카이브에는 포함하고 싶지 않을 때 export-ignore attribute 를 사용한다.



-

아카이브를 만들어서 배포할 때에도 git log 같은 포맷 규칙을 적용할 수 있다.

export-subst attribute 로 설정한 파일들의 키워드가 치환된다.

git archive 명령을 실행할 때 자동으로 마지막 커밋의 메타데이터가 자동으로 삽입되게 할 수 있다.




* Merge 전략


-

파일마다 다른 머지 전략을 사용하도록 할 수 있다.

머지할 때 충돌이 날 것 같은 파일이 있다고 하자.

Git attribute 로 이 파일만 항상 타인의 코드 말고 내 코드를 사용하도록 설정할 수 있다.


ex)

database.xml merge=ours







8.3. Git Hooks


-

이벤트가 생겼을 때 자동으로 특정 스크립트를 실행하도록 할 수 있다.

이 훅은 클라이언트 훅과 서버 훅으로 나눌 수 있다.

클라 훅은 커밋이나 머지할 때 실행되고, 서버 훅은 push 할 떄 서버에서 실행된다.




* 훅 설치하기


-

훅은 git 디렉터리 밑에 hooks 라는 디렉터리에 저장한다.

기본 훅 디렉터리는 .git/hooks 이다.

이 디렉터리에 가보면 git 이 자동으로 넣어준 매우 유용한 스크립트 예제가 몇 개 있다.

셸과 perl, ruby, python 등 다 가능하다.

실행할 수 있는 스크립트 파일을 확장자 없이 저장소의 hooks 디렉터리에 넣으면 훅 스크립트가 켜진다.

이 스크립트는 앞으로 계속 호출된다.




* 클라 훅


-

저장소를 clone 해도 클라 훅이 복사되지 않는다.

만든 정책이 반드시 적용되도록 하려면 서버 훅을 이용해야만 한다.



-

커밋과 관련된 훅은 모두 네 가지다.



-

pre-commit 은 커밋할 때 가장 먼저 호출되며, 커밋 메시지를 작성하기 전에 호출된다. 이 훅에서 커밋하는 snapshot 을 점검한다.

이 훅의 exit 코드가 0이 아니면 커밋은 취소된다.

git commit —no-verify 로 생략할 수 도 있다.

$ git commit --no-verify



-

prepare-commit-msg 훅은 git 이 커밋 매세지를 생성하고 나서 편집기를 실행하기 전에 실행된다.

이 훅은 사람이 커밋 메시지를 수정하기 전에 먼저 프로그램으로 손보고 싶을 때 사용한다.

이 훅은 커밋 메시지가 들어 있는 파일의 경로, 커밋의 종류를 아규먼트로 받는다.

그리고 amending 할 때는 SHA-1 값을 추가 아규먼트로 더 받는다.



-

commit-msg 훅은 커밋 메시지가 들어 있는 임시 파일의 경로를 아규먼트로 받는다.

그리고 이 스크립트가 0이 아닌 값을 반환하면 커밋되지 않는다.

이 훅에서 최종적으로 커밋이 완료되기 전에 프로젝트 상태나 커밋 메시지를 검증한다.



-

커밋이 완료되면 post-commit 훅이 실행된다.



-

이메일 워크플로에 해당하는 클라 훅은 세 가지다.

이 훅은 모두 git am 명령으로 실행된다.

자세한 내용은 생략....



-

pre-rebase 훅은 rebase 하기 전에 실행된다.

post-rewrite 훅은 커밋을 변경하는 명령을 실행했을 때 실행된다. 예를 들어 --amend 나 rebase 등에 해당한다. filter-branch 는 해당하지 않는다.



-

post-merge 훅은 머지가 끝나고 나서 실행된다.

pre-push 훅은 push 명령을 실행하면 동작하는데 리모트 정보를 업데이트 하고 난 후 리모트로 데이터를 전송하기 전에 동작한다.

훅에서 0이 아닌 값을 반환하면 push 를 중지시킨다.



-

git 은 정상적으로 동작하는 중에도 이따금 git gc --auto 명령으로 gc 를 한다.

pre-auto-gc 훅은 gc 가 실행되기 직전에 호출되는 훅이다.




* 서버 훅


-

서버 훅은 모두 push 전후에 실행된다.

push 전에 실행되는 훅이 0이 아닌 값을 반환하면 해당 push 는 거절되고 클라는 에러 메시지를 출력한다.



-

push 하면 가장 처음 실행되는 훅은 pre-receive 훅이다.

이 스크립트는 표준 입력(stdin)으로 push 하는 refs 목록을 입력받는다.

fast-forward push 가 아니면 거절하거나, 브랜치 push 권한을 제어하려면 이 훅에서 하는 것이 좋다.

관리자만 브랜치를 새로 push 하고 삭제할 수 있고 일반 개발자는 수정사항만 push 할 수 있게 할 수 있다.



-

update 스크립트는 각 브랜치마다 한번씩 실행된다는 것을 제외하면 pre-receive 스크립트와 거의 같다.

한 번에 브랜치를 여러 개 push 하면 pre-receive 는 한번 실행되지만, update 는 브랜치마다 실행된다.



-

post-receive 훅은 push 한 후에 실행된다.

이 훅으로 사용자나 서비스에 알림 메시지를 보낼 수 있다.





8.4. 정책 구현하기


-

커밋 메시지 규칙으로 검사하고 fast-forward push 만 허용하고 디렉터리마다 사용자의 수정 권한을 제어하는 워크플로를 만들 수 있다.

실질적으로 정책을 강제하려면 서버 훅으로 만들어야 한다.

개발자들이 push 할 수 없는 커밋은 아예 만들지 않도록 클라 훅도 만드는 것이 좋다.




* 서버 훅


-

자세한 내용 생략!




* 클라 훅


-

서버 훅의 단점은 push 할 때까지 push 할 수 있는지 없는지 알 수 없다는 데 있다.

기껏 정성껏 구현했는데 막상 push 할 수 없으면 곤혹스럽다.

clone 할 때 이 훅은 전송되지 않기 때문에 다른 방법으로 동료에게 배포해야 한다.

그 훅을 가져다 .git/hooks 디렉터리에 복사하고 실행할 수 있게 만든다.

이 훅 파일을 프로젝트에 넣어서 배포해도 되고, git 훅 프로젝트를 만들어 배포해도 된다.



-

자세한 내용은 생략...





8.5. 요약




반응형

댓글