Pro git - 8.1

Updated:

Pro git - Git 설정하기

1. Git 설정하기

  • Git은 먼저 /etc/gitconfig 파일을 찾는다.
  • 이 파일은 해당 시스템에 있는 모든 사용자와 모든 저장소에 적용되는 설정 파일이다.
  • git config 명령에 --system 옵션을 주면 이 파일을 사용한다.
  • 다음으로 ~/.gitconfig 파일을 찾는다.
  • 이 파일은 해당 사용자에게만 적용되는 설정 파일이다.
  • --global 옵션을 주면 Git은 이 파일을 사용한다.
  • 마지막으로 현재 작업 중인 저장소의 Git 디렉토리에 있는 .git/config 파일을 찾는다.
  • 이 파일은 해당 저장소에만 적용된다.
  • git config 명령에 --local 옵션을 적용한 것과 같다. (아무런 범위 옵션을 지정하지 않으면 Git은 기본적으로 --local 옵션을 적용한다)
  • 각 설정 파일에 중복된 설정이 있으면 설명한 “순서대로” 덮어쓴다.
  • 예를 들어 .git/config/etc/gitconfig 에 같은 설정이 들어 있다면 .git/config 에 있는 설정을 사용한다.

2. 클라이언트 설정

  • 설정이 영향을 미치는 대상에 따라 클라이언트 설정과 서버 설정으로 나눠볼 수 있다.
  • 대부분은 개인작업 환경과 관련된 클라이언트 설정이다.
  • Git에는 설정거리가 매우 많은데, 여기서는 워크플로를 관리하는 데 필요한 것과 주로 많이 사용하는 것만 설명한다.
  • Git 버전마다 옵션이 조금씩 다른데, 아래와 같이 실행하면 설치한 버전에서 사용할 수 있는 옵션을 모두 보여준다.
$ man git-config

2.1 core.editor

  • Git은 편집기를 설정($VISUAL, $EDITOR 변수로 설정)하지 않았거나 설정한 편집기를 찾을 수 없으면 vi 를 실행한다.
  • 커밋할 때나 태그 메시지를 편집할 때 설정한 편집기를 실행한다.
  • code.editor 설정으로 편집기를 설정한다.
$ git config --global core.editor emacs
  • 이렇게 설정하면 메시지를 편집할 때 환경변수에 설정한 편집기가 아니라 Emacs를 실행한다.

2.2 commit.template

  • 커밋할 때 Git이 보여주는 커밋 메시지는 이 옵션에 설정한 템플릿 파일이다.
  • 사용자 지정 커밋 템플릿 메시지가 주는 장점은 커밋 메시지를 작성할 때 일정한 스타일을 유지할 수 있다는 점이다.

  • 예를 들어 ~/.gitmessage.txt 파일을 아래와 같이 만든다.
Subject line (try to keep under 50 characters)

Multi-line description of commit,
feel free to be detailed.

[Ticket: X]
  • 커밋 메시지 템플릿을 보면 커밋 메시지를 작성할 때 제목은 일정 길이 이하로 짧게 하고(git log --oneline 으로 보기 좋게) 자세한 수정 내용은 한칸 공백 이후 서술하도록 하고 버그 트래킹 시스템이나 이슈 관리 시스템을 쓸 경우 이슈의 번호를 적도록 유도하고 있는 것을 볼 수 있다.

  • 이 파일을 commit.template 에 설정하면 Git은 git commit 명령이 실행하는 편집기에 이 메시지를 기본으로 넣어준다.

$ git config --global commit.template ~/.gitmessage.txt
$ git commit
  • 그러면 커밋할 때 아래와 같은 메시지를 편집기에 자동으로 채워준다.
Subject line (try to keep under 60 characters)

Multi-line description of commit,
feel free to be detailed.

[Ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C
  • 소속 팀에 커밋 메시지 규칙이 있으면 그 규칙에 맞는 템플릿 파일을 만들고 시스템 설정에 설정해둔다.
  • Git이 그 파일을 사용하도록 설정하면 규칙을 따르기가 쉬워진다.

2.3 core.pager

  • Git은 logdiff 같은 명령의 메시지를 출력할 때 페이지로 나누어 보여준다.
  • 기본으로 사용하는 명령은 less 다. more 를 더 좋아하면 more 라고 설정한다. 페이지를 나누고 싶지 않으면 빈 문자열로 설정한다.
$ git config --global core.pager ''
  • 이 명령을 실행하면 Git은 길든지 짧든지 결과를 한 번에 다 보여 준다.

2.4 user.signingkey

  • 이 설정은 내 작업에 서명하기 에서 설명했던 Annotated Tag를 만들 때 유용하다.
  • 사용할 GPG 키를 설정해 둘 수 있다.
  • 아래처럼 GPG 키를 설정하면 서명할 때 편리하다.
$ git config --global user.signingkey <gpg-key-id>
  • git tag 명령을 실행할 때 키를 생략하고 서명할 수 있다.
$ git tag -s <tag-name>

2.5 core.excludesfile

  • 한 저장소 안에서뿐 아니라 어디에서라도 Git에 포함하지 않을 파일을 설정할 수 있다.
  • 예를 들어 Mac을 쓰는 사람이라면 .DS_Store 파일을 자주 보았을 것이다.
  • Emacs나 Vim를 쓰다 보면 이름 끝에 ~, .swp 붙여둔 임시 파일도 있다.

  • .gitignore 파일처럼 무시할 파일을 설정할 수 있는데 ~/.gitignore_global 파일 안에 아래 내용으로 입력해두고
*~
.*.swp
.DS_Store
  • git config --global core.excludesfile ~/.gitignore_global 명령으로 설정을 추가하면 더는 위와 같은 파일이 포함되지 않을 것이다.

2.6 help.autocorrect

  • 명령어를 잘못 입력하면 Git은 메시지를 아래와 같이 보여 준다.
$ git chekcout master
git: 'chekcout' is not a git command. See 'git --help'.

Did you mean this?
    checkout
  • Git은 어떤 명령을 입력하려고 했을지 추측해서 보여주긴 하지만 직접 실행하진 않는다.
  • 그러나 help.autocorrect 를 1로 설정하면 명령어를 잘못 입력해도 Git이 자동으로 해당 명령어를 찾아서 실행해준다.
$ git chekcout master
WARNING: You called a Git command named 'chekcout', which does not exist.
Continuing under the assumption that you meant 'checkout'
in 0.1 seconds automatically...
  • 여기서 재밌는 것은 “0.1 seconds” 이다.
  • 사실 help.autocorrect 설정에 사용하는 값은 1/10 초 단위의 숫자를 나타낸다.
  • 만약 50이라는 값으로 설정한다면 자동으로 고친 명령을 실행할 때 Git은 5초간 명령을 실행하지 않고 기다려줄 수 있다.

3. 컬러 터미널

  • 사람이 쉽게 인식할 수 있도록 터미널에 결과를 컬러로 출력할 수 있다.
  • 터미널 컬러와 관련된 옵션은 매우 다양하기 때문에 꼼꼼하게 설정할 수 있다.

3.1 color.ui

  • Git은 기본적으로 터미널에 출력하는 결과물을 알아서 색칠하지만, 이 색칠하는 기능을 끄고 싶다면 한 가지 설정만 해 두면 된다.
  • 아래와 같은 명령을 실행하면 더는 색칠된 결과물을 내지 않는다.
$ git config --global color.ui false
  • 컬러 설정의 기본 값은 auto 로 터미널에 출력할 때는 색칠하지만, 결과가 리다이렉션되거나 파일로 출력되면 색칠하지 않는다.

  • always 로 설정하면 터미널이든 다른 출력이든 상관없이 색칠하여 내보낸다.
  • 대개 이 값을 설정해서 사용하지 않는다.
  • --color 옵션을 사용하면 강제로 결과를 색칠해서 내도록 할 수 있기 때문이다.
  • 대부분은 기본 값이 낫다.

3.2 color.*

  • Git은 좀 더 꼼꼼하게 컬러를 설정하는 방법을 제공한다.
  • 아래와 같은 설정들이 있다.
  • 모두 true, false, always 중 하나를 고를 수 있다.
color.branch
color.diff
color.interactive
color.status
  • 또한, 각 옵션의 컬러를 직접 지정할 수도 있다.
  • 아래처럼 설정하면 diff 명령에서 meta 정보의 포그라운드는 blue, 백그라운드는 black, 테스트는 bold로 바뀐다.
$ git config --global color.diff.meta "blue black bold"
  • 컬러는 normal, black, red, green, yellow, blue, magenta, cyan, white 중에서 고를 수 있다.
  • 텍스트 속성은 bold, dim, ul (underline), blink, reverse 중에서 고를 수 있다.

4. 다른 Merge, Diff 도구 사용하기

  • Git에 들어 있는 diff 도구 말고 다른 도구로 바꿀 수 있다.
  • 화려한 GUI 도구로 바꿔서 좀 더 편리하게 충돌을 해결할 수 있다.
  • 여기서는 Perforce의 Merge 도구인 P4Merge로 설정하는 것을 보여준다.
  • P4Merge는 무료인데다 꽤 괜찮다.

  • P4Merge는 중요 플랫폼을 모두 지원하기 때문에 웬만한 환경이면 사용할 수 있다.
  • 여기서는 Mac과 Linux 시스템에 설치하는 것을 보여준다.
  • Windows에서 사용하려면 /usr/local/bin 경로만 Windows 경로로 바꿔준다.

  • 먼저 https://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools 에서 P4Merge를 내려받는다.
  • 그 후에 P4Merge 에 쓸 Wrapper 스크립트를 만든다.
  • 필자는 Mac 사용자라서 Mac 경로를 사용한다.
  • 어떤 시스템이든 p4merge 가 설치된 경로를 사용하면 된다.
  • 예제에서는 extMerge 라는 Merge 용 Wrapper 스크립트를 만들고 이 스크립트로 넘어오는 모든 아규먼트를 p4merge 프로그램으로 넘긴다.
$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*
  • 그리고 diff용 Wrapper도 만든다.
  • 이 스크립트로 넘어오는 아규먼트는 총 7개지만 그 중 2개만 Merge Wrapper로 넘긴다.
  • Git이 diff 프로그램에 넘겨주는 아규먼트는 아래와 같다.
path old-file old-hex old-mode new-file new-hex new-mode
  • 이 중에서 old-filenew-file 만 사용하는 wrapper 스크립트를 만든다.
$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"
  • 이 두 스크립트에 실행 권한을 부여한다.
$ sudo chmod +x /usr/local/bin/extMerge
$ sudo chmod +x /usr/local/bin/extDiff
  • Git config 파일에 이 스크립트를 모두 추가한다.
  • 설정해야 하는 옵션이 좀 많다. merge.tool 로 무슨 Merge 도구를 사용할지, mergetool.*.cmd 로 실제로 어떻게 명령어를 실행할지, mergetool.trustExitCode 로 Merge 도구가 반환하는 exit 코드가 Merge의 성공 여부를 나타내는지, diff.external 은 diff 할 때 실행할 명령어가 무엇인지를 설정할 때 사용한다.
  • 모두 git config 명령으로 설정한다.
$ 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
  • ~/.gitconfig/ 파일을 직접 편집해도 된다.
[merge]
  tool = extMerge
[mergetool "extMerge"]
  cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
  trustExitCode = false
[diff]
  external = extDiff
  • 설정을 완료하고 나서 아래와 같이 diff 명령어를 실행한다.
$ git diff 32d1776b1^ 32d1776b1
  • diff 결과가 터미널에 출력되는 대신 P4Merge가 실행되어 아래처럼 Diff 결과를 보여준다.

https://git-scm.com/book/en/v2/images/p4merge.png

  • 브랜치를 Merge 할 때 충돌이 나면 git mergetool 명령을 실행한다.
  • 이 명령을 실행하면 GUI 도구로 충돌을 해결할 수 있도록 P4Merge를 실행해준다.

  • Wrapper를 만들어 설정해두면 다른 Diff, Merge 도구로 바꾸기도 쉽다.
  • 예를 들어, KDiff3를 사용하도록 extDiffextMerge 스크립트를 수정한다.
$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*
  • 이제부터 Git은 Diff 결과를 보여주거나 충돌을 해결할 때 KDiff3 도구를 사용한다.

  • 어떤 Merge 도구는 Git에 미리 설정이 들어 있다.
  • 그래서 추가로 스크립트를 작성하거나 하는 설정 없이 사용할 수 있는 것도 있다. 아래와 같은 명령으로 확인해볼 수 있다.
$ git mergetool --tool-help
'git mergetool --tool=<tool>' may be set to one of the following:
        emerge
        gvimdiff
        gvimdiff2
        opendiff
        p4merge
        vimdiff
        vimdiff2

The following tools are valid, but not currently available:
        araxis
        bc3
        codecompare
        deltawalker
        diffmerge
        diffuse
        ecmerge
        kdiff3
        meld
        tkdiff
        tortoisemerge
        xxdiff

Some of the tools listed above only work in a windowed
environment. If run in a terminal-only session, they will fail.
  • Diff 도구로는 다른 것을 사용하지만, Merge 도구로는 KDiff3를 사용하고 싶은 경우에는 kdiff3 명령을 실행경로로 넣고 아래와 같이 설정하기만 하면 된다.
$ git config --global merge.tool kdiff3
  • extMergeextDiff 파일을 만들지 않고 이렇게 Merge 도구만 kdiff3로 설정하고 Diff 도구는 Git에 원래 들어 있는 것을 사용할 수 있다.

5. Formatting and Whitespace

  • 협업할 때 겪는 소스 포맷(Formatting)과 공백 문제는 미묘하고 난해하다.
  • 동료 사이에 사용하는 플랫폼이 다를 때는 특히 더 심하다.
  • 다른 사람이 보내온 Patch는 공백 문자 패턴이 미묘하게 다를 확률이 높다.
  • 편집기가 몰래 공백문자를 추가해 버릴 수도 있고 크로스-플랫폼 프로젝트에서 Windows 개발자가 라인 끝에 CR(Carriage-Return) 문자를 추가해 버렸을 수도 있다.
  • Git에는 이 이슈를 돕는 몇 가지 설정이 있다.

5.1 core.autocrlf

  • Windows에서 개발하는 동료와 함께 일하면 라인 바꿈(New Line) 문자에 문제가 생긴다.
  • Windows는 라인 바꿈 문자로 CR(Carriage-Return)과 LF(Line Feed) 문자를 둘 다 사용하지만, Mac과 Linux는 LF 문자만 사용한다.
  • 아무것도 아닌 것 같지만, 크로스 플랫폼 프로젝트에서는 꽤 성가신 문제다.
  • Windows에서 사용하는 많은 편집기가 자동으로 LF 스타일의 라인 바꿈 스타일을 CRLF로 바꾸거나 Enter 키를 입력하면 CRLF 스타일을 사용하기 때문이다.

  • Git은 커밋할 때 자동으로 CRLF를 LF로 변환해주고 반대로 Checkout 할 때 LF를 CRLF로 변환해 주는 기능이 있다. core.autocrlf 설정으로 이 기능을 켤 수 있다.
  • Windows에서 이 값을 true로 설정하면 Checkout 할 때 LF 문자가 CRLF 문자로 변환된다.
$ git config --global core.autocrlf true
  • 라인 바꿈 문자로 LF를 사용하는 Linux와 Mac에서는 Checkout 할 때 Git이 LF를 CRLF로 변환할 필요가 없다.
  • 게다가 우연히 CRLF가 들어간 파일이 저장소에 들어 있어도 Git이 알아서 고쳐주면 좋을 것이다.
  • core.autocrlf 값을 input으로 설정하면 커밋할 때만 CRLF를 LF로 변환한다.
$ git config --global core.autocrlf input
  • 이 설정을 이용하면 Windows에서는 CRLF를 사용하고 Mac, Linux, 저장소에서는 LF를 사용할 수 있다.

  • Windows 플랫폼에서만 개발하면 이 기능이 필요 없다.
  • 이 옵션을 false 라고 설정하면 이 기능이 꺼지고 CR 문자도 저장소에도 저장된다.
$ git config --global core.autocrlf false

5.2 core.whitespace

  • Git에는 공백 문자를 다루는 방법으로 네 가지가 미리 정의돼 있다.
  • 두 가지는 기본적으로 켜져 있지만 끌 수 있고 나머지 두 가지는 꺼져 있지만 켤 수 있다.

  • 먼저 기본적으로 켜져 있는 것을 살펴보자.
  • blank-at-eol 는 각 라인 끝에 공백이 있는지 찾고, blank-at-eof 는 파일 끝에 추가한 빈 라인이 있는지 찾고, space-before-tab 은 모든 라인에서 처음에 tab보다 공백이 먼저 나오는지 찾는다.

  • 기본적으로 꺼져 있는 나머지 세 개는 indent-with-non-tabtab-in-indentcr-at-eol 이다.
  • intent-with-non-tab 은 tab이 아니라 공백으로(tabwidth 설정에 영향받음) 시작하는 라인이 있는지 찾고 cr-at-eol 은 라인 끝에 CR 문자가 있어도 괜찮다고 Git에 알리는 것이다.

  • core.whitespace 옵션으로 이 네 가지 방법을 켜고 끌 수 있다.
  • 설정에서 해당 옵션을 빼버리거나 이름이 - 로 시작하면 기능이 꺼진다.
  • 예를 들어, 다른 건 다 켜고 space-before-tab 옵션만 끄려면 아래와 같이 설정한다.
  • trailing-space 옵션은 blank-at-eol 옵션과 blank-at-eof 옵션을 의미한다.
$ git config --global core.whitespace \
    trailing-space,-space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol
  • 또는 각 부분에 대해서 설정을 할 수도 있다.
$ git config --global core.whitespace \
    -space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol
  • git diff 명령을 실행하면 Git은 이 설정에 따라 검사해서 컬러로 표시해준다.
  • 그래서 좀 더 쉽게 검토해서 커밋할 수 있다.
  • git apply 명령으로 Patch를 적용할 때도 이 설정을 이용할 수 있다.
  • 아래처럼 명령어를 실행하면 해당 Patch가 공백문자 정책에 들어맞는지 확인할 수 있다.
$ git apply --whitespace=warn <patch>
  • 아니면 Git이 자동으로 고치도록 할 수 있다.
$ git apply --whitespace=fix <patch>
  • 이 옵션은 git rebase 명령에서도 사용할 수 있다.
  • 공백 문제가 있는 커밋을 Upstream에 Push 하기 전에 --whitespace=fix 옵션을 주고 Rebase 하면 Git은 다시 Patch를 적용하면서 공백을 설정한 대로 고친다.

6. 서버 설정

  • 서버 설정은 많지 않지만, 꼭 짚고 넘어가야 하는 것이 몇 개 있다.

6.1 receive.fsckObjects

  • Git은 Push 할 때마다 각 개체가 SHA-1 체크섬에 맞는지 잘못된 개체가 가리키고 있는지 검사하게 할 수 있다.
  • 기본적으로 이 기능이 동작하지 않게 설정이 되어 있는데 개체를 점검하데 상당히 시간이 걸리기 때문에 Push 하는 시간이 늘어난다.
  • 얼마나 늘어나는지는 저장소 크기와 Push 하는 양에 달렸다.
  • receive.fsckOBjects 값을 true로 설정하면 Git이 Push 할 때마다 검증한다.
$ git config --system receive.fsckObjects true
  • 이렇게 설정하면 Push 할 때마다 검증하기 때문에 클라이언트는 잘못된 데이터를 Push 하지 못한다.

6.2 receive.denyNonFastForwards

  • 이미 Push 한 커밋을 Rebase 해서 다시 Push 하지 못하게 할 수 있다.
  • 브랜치를 Push 할 때 해당 리모트 브랜치가 가리키는 커밋이 Push 하려는 브랜치에 없을 때 Push 하지 못하게 할 수 있다.
  • 보통은 이런 정책이 좋고 git push 명령에 -f 옵션을 주면 강제로 Push 할 수 있다.

  • receive.denyNonFastForwards 옵션을 켜면 Fast-forward로 Push 할 수 없는 브랜치는 아예 Push 하지 못한다.
$ git config --system receive.denyNonFastForwards true
  • 사용자마다 다른 정책을 적용하고 싶으면 서버 훅을 사용해야 한다.
  • 서버의 receive 훅으로 할 수 있고 이 훅도 이 장에서 설명한다.

6.2 receive.denyDeletes

  • receive.denyNonFastForwards 와 비슷한 정책으로 receive.denyDeletes 라는 것이 있다.
  • 이 설정을 켜면 브랜치를 삭제하는 Push가 거절된다.
$ git config --system receive.denyDeletes true
  • 이제 브랜치나 Tag를 삭제하는 Push는 거절된다.
  • 아무도 삭제할 수 없다.
  • 리모트 브랜치를 삭제하려면 직접 손으로 server의 ref 파일을 삭제해야 한다.
  • 그리고 사용자마다 다른 정책을 적용시키는 ACL을 만드는 방법도 있다.