Git
Chapters ▾ 2nd Edition

10.8 Git의 내부 - 환경변수

환경변수

Git은 늘 bash 셸 환경 안에서 동작한다. 셸 환경변수에 따라 Git의 동작이 달라진다. Git에 영향을 주는 환경변수가 어떤 것들이 있고 또 그 값에 따라 Git이 어떻게 동작하는지 알아두면 꽤 쓸모 있다. Git과 관련된 환경변수 전체를 다루지는 못하지만 알아두면 유용한 변수들은 거의 다 다룬다.

Git에 영향을 주는 변수

Git의 여러 기능 중 일반적인 기능이 동작할 때 영향을 미치는 주요 환경변수는 아래와 같다.

*GIT_EXEC_PATH * 변수는 Git의 여러 Subprogram(예를 들어 git-commit, git-diff 같은 것들)이 어디에 있는지를 설정한다. 현재 설정을 확인하려면 git --exec-path 명령을 실행한다.

*HOME * 변수는 일반적으로 변경하지 않는 변수이다. 아주 많은 프로그램이 이 변수를 참조하기 때문이다. Git이 이 변수에 영향을 받는 부분은 사용자(User) 전체에 영향을 주는 Git 환경설정 파일을 찾을 때이다. Git을 포터블로 설치하거나 해서 사용자 환경설정 파일의 위치를 강제로 지정해야 하면 Git을 실행하는 셸의 HOME 변수에 원하는 값을 설정한다.

*PREFIX * 변수도 비슷한 성격으로 사용자 수준이 아닌 시스템 수준의 환경설정 파일을 찾을 위치를 설정한다. Git이 찾을 위치는 $PREFIX/etc/gitconfig 이다.

*GIT_CONFIG_NOSYSTEM * 변수를 설정하면 시스템 수준의 환경설정 파일을 적용하지 않는다. 이 변수는 시스템 수준의 환경설정 파일이 자꾸 방해되는데 고칠 권한이 없는 경우 설정하면 유용하다.

*GIT_PAGER * 변수는 Git이 화면에 출력할 내용이 한 화면이 넘어갈 때 사용할 프로그램을 설정한다. 이 변수에 값을 설정하지 않으면 PAGER 변수의 내용도 참고한다.

*GIT_EDITOR * 변수는 커밋 내용을 입력하는 상황과 같이 Git이 사용자로부터 어떤 내용을 입력받는 경우 실행시킬 편집기를 설정하는 변수이다. 이 변수에 값을 설정하지 않으면 EDITOR 변수의 내용도 참고한다.

저장소 위치 관련 변수

Git은 현재 작업 중인 저장소를 참조할 때 아래와 같은 환경변수에 영향을 받는다.

*GIT_DIR * 변수는 .git 디렉토리의 위치를 설정하는 변수다. 이 변수의 값을 설정하지 않으면 현재 디렉토리에서부터 ~/ 까지 한 단계씩 위로 올라가면서 .git 디렉토리가 있는지 찾는다.

*GIT_CEILING_DIRECTORIES * 변수는 .git 디렉토리를 찾으려고 한 단계씩 위로 올라가는 작업을 제어한다. 사용하는 시스템의 저장장치를 읽고 쓰는 속도가 무지하게 느리면 이 변수를 적절하게 설정한다. 불필요하게 .git 디렉토리를 찾아서 계속 저장장치의 디렉토리를 돌아다니지 않아도 된다.

*GIT_WORK_TREE * 변수는 Git 저장소가 관리하는 실제 소스코드와 같은 파일이 위치한 디렉토리를 설정한다. 물론 실제 파일을 사용하므로 Bare 저장소가 아닌 경우에만 해당한다. --git-dir 옵션이나 GIT_DIR 변수가 지정되었으나 --work-tree 옵션 또는 GIT_WORK_TREE 변수 또는 core.worktree 설정이 지정되지 않으면 현재 디렉토리를 워킹 디렉토리의 최상위 디렉토리로 가정한다.

*GIT_INDEX_FILE * 변수는 Index 파일의 위치를 설정한다. Bare 저장소가 아닌 경우에만 해당한다.

*GIT_OBJECT_DIRECTORY * 변수는 .git/objects 디렉토리 위치를 설정한다. Bare 저장소가 아닌 경우에만 해당한다.

*GIT_ALTERNATE_OBJECT_DIRECTORIES * 변수는 콜론으로 구분된 디렉토리 리스트(예, /dir/one:/dir/two:…)로 GIT_OBJECT_DIRECTORY 에서 찾을 수 없는 개체를 찾을 때 사용할 디렉토리를 설정한다. 크기가 무지하게 큰 파일을 여러 프로젝트에서 공유하고 있다면 이 변수를 적절히 사용한다. 중복되는 내용을 지우고 특정 위치에서 개체를 공유해서 사용하므로 저장공간 낭비를 줄일 수 있다.

Pathspec 관련 변수

“pathspec” 은 Git을 쓸 때 파일이나 디렉토리의 경로(* 같은 와일드카드 문자를 사용하는 경우를 포함)를 전달할 때 어떤 방식을 사용하는가에 대한 내용이다. .gitignore 파일에서도 사용하고 git 명령(예, git add *.c)에서도 사용한다.

GIT_GLOB_PATHSPECS, GIT_NOGLOB_PATHSPECS 변수로는 Pathspec을 사용할 때 와일드카드 문자로 어떤 동작을 하게 할 지 설정한다. GIT_GLOB_PATHSPECS 변수의 값을 1로 설정하면 와일드카드 문자는 보통 사용하듯 와일드카드 문자의 역할을 한다(기본값). GIT_NOGLOB_PATHSPECS 변수의 값을 1로 설정하면 와일드카드 문자를 진짜 파일 이름의 와일드카드 문자로만 인식한다. *.c 라고 하면 진짜 파일 이름이 “*.c” 인 파일만 해당하고 확장자가 .c 파일은 해당하지 않는다. 환경 변수에 독립적으로 각 명령에서 이를 선택하여 사용할 때는 :(glob) 또는 :(literal) 를 명시해서 사용할 수 있다. 예를 들어 :(glob)*.c 같이 말이다.

*GIT_LITERAL_PATHSPECS * 변수를 설정하면 위 설정 둘 다 적용하지 않는다. 와일드카드 문자는 아무런 쓸모도 없게 되고, 변수에 독립적으로 사용하는 접두어도 마찬가지로 쓸 수 없게 된다.

*GIT_ICASE_PATHSPECS * 변수를 설정하면 대문자와 소문자를 가리지 않게 된다.

커밋관련 변수

Git이 커밋을 만드는 작업에서 대부분 git-commit-tree 명령을 실행하고 나면 커밋 개체가 만들어진다. 이 명령이 커밋을 만들 때 커밋에 채워넣을 정보를 가져오거나 참고하는 환경변수는 아래와 같다. 환경변수를 설정하지 않는 경우는 환경설정 파일의 내용을 가져와 적용한다.

*GIT_AUTHOR_NAME * 변수는 “author” 정보로 사용할 이름.

*GIT_AUTHOR_EMAIL * 변수는 “author” 정보로 사용할 이메일 주소.

*GIT_AUTHOR_DATE * 변수는 “author” 정보로 사용할 타임스탬프 값.

*GIT_COMMITTER_NAME * 변수는 “committer” 정보로 사용할 이름.

*GIT_COMMITTER_EMAIL * 변수는 “committer” 정보로 사용할 이메일 주소.

*GIT_COMMITTER_DATE * 변수는 “committer” 정보로 사용할 타임스탬프 값.

*EMAIL * 변수는 어떤 환경설정 파일에도 user.email 설정을 찾을 수 없는 경우 참조하는 변수다. 이 변수마저 설정하지 않으면 Git은 시스템의 현재 사용자정보와 시스템 호스트 정보를 조합하여 사용한다.

네트워크 관련 변수

Git은 HTTP 프로토콜로 데이터를 전송할 때 curl 라이브러리를 사용한다. GIT_CURL_VERBOSE 변수를 설정하면 curl 라이브러리가 출력하는 상세한 정보를 볼 수 있다. curl -v 명령을 사용한 경우와 비슷하다.

GIT_SSL_NO_VERIFY 변수를 설정하면 SSL 인증서를 확인하지 않는다. HTTPS 프로토콜로 저장소를 사용하는데 Self-signed 인증서를 사용할 때 이 변수를 사용한다. 혹은 아직 인증서를 정상적으로 발급하진 않았지만, 테스트를 위해 테스트용 인증서를 사용하는 경우를 예로 들 수도 있다.

GIT_HTTP_LOW_SPEED_TIME 변수에 설정한 시간 동안 GIT_HTTP_LOW_SPEED_LIMIT 변수에 설정한 초당 전송 바이트 수에 미치지 못하는 HTTP 전송속도가 나오면 Git은 데이터 전송을 중지한다. 이 설정은 설정파일의 http.lowSpeedLimit, http.lowSpeedTime 항목보다 우선한다.

GIT_HTTP_USER_AGENT 변수는 Git이 HTTP 데이터 전송을 할 때 헤더에 사용자 에이전트 값으로 사용할 문자열을 설정한다. 기본적으로 사용하는 값은 git/2.0.0 같은 모양의 값이다.

Diff/Merge 관련 변수

*GIT_DIFF_OPTS * 변수는 이름이 잘못 지어진 변수다. git diff 명령을 실행했을 때 변경된 부분 아래위로 보여주는 라인의 개수를 조절한다. 명령의 옵션으로 사용할 때는 -u<n> 이나 `--unified=<n>`로 사용한다.

*GIT_EXTERNAL_DIFF * 변수는 diff.external 설정보다 우선한다. git diff 명령을 실행하면 이 변수에 설정한 명령을 실행한다.

*GIT_DIFF_PATH_COUNTER * 변수나 *GIT_DIFF_PATH_TOTAL * 변수의 설정은 GIT_EXTERNAL_DIFF 또는 diff.external 에 설정된 프로그램 안에서 유용하게 사용한다. GIT_DIFF_PATH_TOTAL 변수는 diff 명령이 실행할 때 보여주는 모든 파일의 개수를 나타낸다. GIT_DIFF_PATH_COUNTER 변수는 그 파일 중 지금 몇 번째 파일을 보여주고 있는지를 1로 시작하는 Index를 담고 있다.

*GIT_MERGE_VERBOSITY * 변수는 Recursive Merge 전략에 따른 메시지 출력을 제어한다. 이 변수가 사용할 수 있는 값은 아래와 같이 5개의 수준이다.

  • 0 충돌이 발생한 경우에만 마지막 에러 메시지를 출력

  • 1 충돌이 발생한 경우에만 충돌 내용을 출력함

  • 2 충돌 내용과 변경된 내용을 출력함

  • 3 변경된 내용이 없는 파일이라도 출력함

  • 4 Merge 할 때 열어본 모든 파일을 출력함

  • 5 또는 그 이상의 값을 설정하면 디버그 메시지까지 출력함

이 중 기본 값은 2이다.

디버그 관련 변수

Git이 어디까지 실행했는지 알고 싶은가? Git은 거의 모든 내부 동작에 대한 Trace 로그를 남길 수 있으며 환경변수를 조절해서 Trace 로그를 확인할 수 있다. 변수에 설정할 수 있는 값은 아래와 같다.

  • “true”, “1”, “2” – stderr 표준에러출력으로 Trace 로그를 출력함(1 이상 10 이하의 숫자는 해당 FD로 출력함).

  • / 로 시작하는 절대 경로 – Trace 로그를 해당 경로의 파일에 기록함.

*GIT_TRACE * 변수에 위와 같은 값을 설정하면 특정 카테고리로 지정하지 않은 모든 Trace 메시지를 대상에 기록하거나 출력한다. Alias를 적용하거나 명령에 따라 Subprogram을 실행시킨다거나 하는 Trace를 확인할 수 있다.

$ GIT_TRACE=true git lga
20:12:49.877982 git.c:554               trace: exec: 'git-lga'
20:12:49.878369 run-command.c:341       trace: run_command: 'git-lga'
20:12:49.879529 git.c:282               trace: alias expansion: lga => 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.879885 git.c:349               trace: built-in: git 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.899217 run-command.c:341       trace: run_command: 'less'
20:12:49.899675 run-command.c:192       trace: exec: 'less'

*GIT_TRACE_PACK_ACCESS * 변수에 따라 Packfile 사용 내용을 출력한다. 출력 내용을 보면 첫 번째 열은 접근하는 Packfile의 이름을, 두 번째 열은 Packfile 안에서 오프셋 정보를 보여준다.

$ GIT_TRACE_PACK_ACCESS=true git status
20:10:12.081397 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 12
20:10:12.081886 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 34662
20:10:12.082115 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 35175
# […]
20:10:12.087398 sha1_file.c:2088        .git/objects/pack/pack-e80e...e3d2.pack 56914983
20:10:12.087419 sha1_file.c:2088        .git/objects/pack/pack-e80e...e3d2.pack 14303666
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

*GIT_TRACE_PACKET * 변수는 네트워크 데이터 전송을 하는 경우 패킷 수준의 Trace 정보를 보여준다.

$ GIT_TRACE_PACKET=true git ls-remote origin
20:15:14.867043 pkt-line.c:46           packet:          git< # service=git-upload-pack
20:15:14.867071 pkt-line.c:46           packet:          git< 0000
20:15:14.867079 pkt-line.c:46           packet:          git< 97b8860c071898d9e162678ea1035a8ced2f8b1f HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master agent=git/2.0.4
20:15:14.867088 pkt-line.c:46           packet:          git< 0f20ae29889d61f2e93ae00fd34f1cdb53285702 refs/heads/ab/add-interactive-show-diff-func-name
20:15:14.867094 pkt-line.c:46           packet:          git< 36dc827bc9d17f80ed4f326de21247a5d1341fbc refs/heads/ah/doc-gitk-config
# […]

*GIT_TRACE_PERFORMANCE * 변수를 설정하면 Git의 성능에 관련된 Trace를 출력한다. 출력한 내용을 살펴보면 어떤 작업이 얼마나 시간이 걸려 실행되었는지 확인할 수 있다.

$ GIT_TRACE_PERFORMANCE=true git gc
20:18:19.499676 trace.c:414             performance: 0.374835000 s: git command: 'git' 'pack-refs' '--all' '--prune'
20:18:19.845585 trace.c:414             performance: 0.343020000 s: git command: 'git' 'reflog' 'expire' '--all'
Counting objects: 170994, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (43413/43413), done.
Writing objects: 100% (170994/170994), done.
Total 170994 (delta 126176), reused 170524 (delta 125706)
20:18:23.567927 trace.c:414             performance: 3.715349000 s: git command: 'git' 'pack-objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--reflog' '--unpack-unreachable=2.weeks.ago' '--local' '--delta-base-offset' '.git/objects/pack/.tmp-49190-pack'
20:18:23.584728 trace.c:414             performance: 0.000910000 s: git command: 'git' 'prune-packed'
20:18:23.605218 trace.c:414             performance: 0.017972000 s: git command: 'git' 'update-server-info'
20:18:23.606342 trace.c:414             performance: 3.756312000 s: git command: 'git' 'repack' '-d' '-l' '-A' '--unpack-unreachable=2.weeks.ago'
Checking connectivity: 170994, done.
20:18:25.225424 trace.c:414             performance: 1.616423000 s: git command: 'git' 'prune' '--expire' '2.weeks.ago'
20:18:25.232403 trace.c:414             performance: 0.001051000 s: git command: 'git' 'rerere' 'gc'
20:18:25.233159 trace.c:414             performance: 6.112217000 s: git command: 'git' 'gc'

*GIT_TRACE_SETUP * 변수를 설정하면 Git이 현재 어떤 저장소와 어떤 환경 위에서 동작하고 있는지 파악한 정보를 보여준다.

$ GIT_TRACE_SETUP=true git status
20:19:47.086765 trace.c:315             setup: git_dir: .git
20:19:47.087184 trace.c:316             setup: worktree: /Users/ben/src/git
20:19:47.087191 trace.c:317             setup: cwd: /Users/ben/src/git
20:19:47.087194 trace.c:318             setup: prefix: (null)
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

잡동사니 변수

*GIT_SSH * 변수를 설정하면 Git이 SSH 리모트로 연결할 때 ssh 명령 대신 설정된 명령을 사용한다. 즉 $GIT_SSH [username@]host [-p <port>] <command> 명령을 실행한 것과 같다. GIT_SSH 변수를 설정하는 방식이 ssh 명령을 사용자 입맛에 맞게끔 고치는 가장 좋은 방법은 아니다. ssh 명령의 다양한 옵션을 사용할 수 없는 방식이기 때문이다. 따로 원하는 옵션들을 적용한 스크립트를 하나 만들고 이 스크립트를 변수에 설정하면 원하는 ssh 옵션을 사용할 수 있다. ~/.ssh/config 환경설정 파일을 편집하여 사용하는 것이 더 나을 수도 있다.

*GIT_ASKPASS * 변수는 core.askpass 설정보다 우선한다. 이 변수에 설정하는 스크립트나 프로그램은 Git이 사용자에게 암호를 입력받는 상황에서 실행되어 stdout 표준출력으로 출력하는 메시지를 암호로 받아서 처리한다. (Credential 저장소 에서 더 자세한 내용을 확인할 수 있다.)

*GIT_NAMESPACE * 변수를 설정하면 Ref에 접근할 때 네임스페이스로 사용한다. --namespace 옵션과 같다. 이 변수는 서버 측에서 유용하게 사용할 수 있다. 하나의 저장소 안에 여러 Fork를 운영하는 경우 이 변수를 사용하여 Ref를 분리하여 사용할 수 있다.

*GIT_FLUSH * 변수를 설정하면 Git이 메시지를 화면에 출력할 때 버퍼를 사용하지 않고 즉시즉시 출력한다. 값을 1로 설정하면 평소보다 훨씬 빈번하게 메시지 출력하고 0으로 설정하면 항상 버퍼를 사용한다. 이 변수에 값을 설정하지 않으면 기본적으로 Git은 상황에 맞게 조절하여 출력한다.

*GIT_REFLOG_ACTION * 변수는 reflog 의 설명에 사용된다. 이 변수에 작업 내용에 대한 설명을 담아두고 Git 명령을 실행하면 된다. 예를 들어 아래와 같다.

$ GIT_REFLOG_ACTION="my action" git commit --allow-empty -m 'my message'
[master 9e3d55a] my message
$ git reflog -1
9e3d55a HEAD@{0}: my action: my message