Git 설정 우선순위 테스터
git 설정 파일을 붙여 넣으면 키마다 어떤 값이 이기는지, 그 값이 나온 범위·파일·줄, 무엇을 덮었는지, 어떤 includeIf가 걸렸는지 보여줍니다.
gitdir: 조건은 <저장소>/.git 경로와, onbranch: 는 브랜치 이름과 대조합니다. hasconfig: 는 설정 내용만으로 판정하므로 둘 다 필요 없습니다.
읽은 파일
6
해석한 키
10
덮인 값이 있는 키
3
따라간 include
2
발견 사항
1
마지막에 읽힌 항목이 이깁니다. 이 열이 git config --get의 결과이고, 덮인 값 열은 --get-all의 나머지를 읽은 순서대로 보여 줍니다.
| 키 | 값 | 범위 · 파일:줄 | bool / int 해석 | 덮인 값 |
|---|---|---|---|---|
| user.name | Ada L. | local .git/config:13 | bool 해당 없음 · int 해당 없음 | 1 앞선 후보(오래된 순):
|
| user.email | ada@release.example | worktree .git/config.worktree:2 | bool 해당 없음 · int 해당 없음 | 2 앞선 후보(오래된 순):
|
| core.autocrlf | input | system /etc/gitconfig:2 | bool 해당 없음 · int 해당 없음 | 유일한 후보 |
| core.pager | delta | global ~/.gitconfig:5 | bool 해당 없음 · int 해당 없음 | 유일한 후보 |
| core.bigfilethreshold | 20m | global ~/.gitconfig:6 | bool true · int 20971520 | 유일한 후보 |
| commit.gpgsign | true | global ~/.gitconfig-work:4 | bool true · int 해당 없음 | 유일한 후보 |
| push.default | current | global ~/.gitconfig-feature:2 | bool 해당 없음 · int 해당 없음 | 유일한 후보 |
| remote.origin.url | git@github.com:acme/app.git | local .git/config:9 | bool 해당 없음 · int 해당 없음 | 유일한 후보 |
| remote.origin.fetch | +refs/tags/*:refs/tags/* | local .git/config:11 | bool 해당 없음 · int 해당 없음 | 1 앞선 후보(오래된 순):
|
| init.defaultbranch | main | system /etc/gitconfig:4 | bool 해당 없음 · int 해당 없음 | 유일한 후보 |
들여 쓴 파일은 바로 위 파일이 불러온 것입니다. 취소선이 그어진 줄은 조건이 맞지 않아 건너뛴 파일입니다.
- system /etc/gitconfig · 이 범위의 파일
- global ~/.gitconfig · 이 범위의 파일
- global ~/.gitconfig-work · includeIf gitdir:~/work/ · 조건 일치
- global ~/.gitconfig-oss · includeIf gitdir:~/oss/ · 건너뜀 — 패턴이 맞지 않음
- global ~/.gitconfig-feature · includeIf onbranch:feature/ · 조건 일치
- local .git/config · 이 범위의 파일
- worktree .git/config.worktree · 이 범위의 파일
git config --list --show-scope --show-origin과 같으며, include된 내용은 지시문이 있던 자리에 그대로 끼워 넣습니다.
| 범위 | 범위 · 파일:줄 | 키 | 값 |
|---|---|---|---|
| system | /etc/gitconfig:2 | core.autocrlf | input |
| system | /etc/gitconfig:4 | init.defaultbranch | main |
| global | ~/.gitconfig:2 | user.name | Ada Lovelace |
| global | ~/.gitconfig:3 | user.email | ada@personal.example |
| global | ~/.gitconfig:5 | core.pager | delta |
| global | ~/.gitconfig:6 | core.bigfilethreshold | 20m |
| global | ~/.gitconfig:8 | includeif.gitdir:~/work/.path | ~/.gitconfig-work |
| global | ~/.gitconfig-work:2 | user.email | ada@corp.example |
| global | ~/.gitconfig-work:4 | commit.gpgsign | true |
| global | ~/.gitconfig:10 | includeif.gitdir:~/oss/.path | ~/.gitconfig-oss |
| global | ~/.gitconfig:12 | includeif.onbranch:feature/.path | ~/.gitconfig-feature |
| global | ~/.gitconfig-feature:2 | push.default | current |
| local | .git/config:2 | core.repositoryformatversion | 0 |
| local | .git/config:3 | core.filemode | true |
| local | .git/config:4 | core.bare | false |
| local | .git/config:5 | core.logallrefupdates | true |
| local | .git/config:7 | extensions.worktreeconfig | true |
| local | .git/config:9 | remote.origin.url | git@github.com:acme/app.git |
| local | .git/config:10 | remote.origin.fetch | +refs/heads/*:refs/remotes/origin/* |
| local | .git/config:11 | remote.origin.fetch | +refs/tags/*:refs/tags/* |
| local | .git/config:13 | user.name | Ada L. |
| worktree | .git/config.worktree:2 | user.email | ada@release.example |
아래는 모두 git이 말없이 넘어가거나 아예 거부하는 상황입니다.
- extensions.worktreeConfig가 켜져 있는데 core.repositoryFormatVersion은 0입니다 — git 2.43은 그래도 읽지만 예전 버전은 무시할 수 있습니다: .git/config
모든 계산은 브라우저 안에서 이루어집니다. 아무것도 업로드하지 않고 어떤 저장소도 건드리지 않습니다.
사용법
- 첫 번째 상자에 설정 파일을 차례로 붙여 넣고, 각 파일 앞에
# system: /etc/gitconfig,# global: ~/.gitconfig,# local: .git/config,# worktree: .git/config.worktree같은 표시 줄을 넣으세요. 대상 컴퓨터에서git config --list --show-origin --show-scope를 돌리면 어떤 파일이 어디에 있는지 그대로 나옵니다. - include가 가리키는 파일은
# file: <경로>로 추가하세요. 이 파일들은 독립된 범위가 아니라 자신을 불러온 파일의 범위를 물려받습니다. 상대 경로include.path는 그 지시문이 적힌 파일의 디렉터리를 기준으로 풀리므로,.git/config안의../work.gitconfig는 저장소 위가 아니라<저장소>/work.gitconfig를 뜻합니다. - 두 번째 상자에 알고 싶은 키를 한 줄에 하나씩 적으세요.
user.email,remote.origin.url,core.autocrlf처럼요. 비워 두면 붙여 넣은 파일들이 정의한 모든 키를 보여 주므로, 있는 줄도 몰랐던 설정을 찾기에 좋습니다. - 저장소 디렉터리와 체크아웃된 브랜치를 채워 넣으세요. 이 두 가지는 파일에 담기지 않는 정보라, 없으면
gitdir:이나onbranch:조건을 판정할 수 없습니다. 비어 있으면 파일 목록에 그렇게 적힙니다. - 표에서 이긴 값과 그 범위·파일·줄을 확인하고, 그 아래에서 밀려난 후보들을 읽은 순서대로 보세요. 이어서 파일 목록으로 include 사슬과 각 조건이 왜 걸렸는지 또는 왜 안 걸렸는지 확인하고, 발견 사항 패널에서 없는 파일을 가리키는 include나 git이 조용히 무시하는 worktree 파일을 찾아보세요.
자세한 설명
펼치기접기
내 컴퓨터에서는 git config --get user.email 한 줄이면 끝나지만, CI 러너나 컨테이너, 동료의 노트북, 혹은 붙여 넣은 파일만 잔뜩 들어 있는 문의 티켓에서는 그럴 수 없습니다. 그럴 때 파일을 여기에 붙여 넣으면 git이 하는 해석을 그대로 재현합니다. # system:, # global:, # local:, # worktree: 표시로 각 파일을 구분해 두면 git이 읽는 순서대로 모든 항목을 늘어놓고, 물어본 키마다 이긴 값과 그 값이 나온 파일·줄, 그리고 그 값이 밀어낸 후보들을 보여줍니다.
규칙은 생각보다 단순합니다. system → global → local → worktree 순서로, 각 파일 안에서는 위에서 아래로 읽고, 마지막에 읽힌 항목이 곧 값입니다. 병합도 없고 '더 구체적인 설정이 이긴다'는 개념도 없습니다. 그래서 .git/config 아래쪽의 두 번째 [user] 섹션이 위쪽을 이기고, include 뒤에 적은 키가 그 include가 불러온 파일을 이깁니다. include는 마지막에 덧붙는 것이 아니라 지시문이 있던 자리에 그대로 끼워 넣어지기 때문입니다. --get과 --get-all이 다른 이유도 같습니다. 앞의 것은 마지막 후보 하나를, 뒤의 것은 읽은 순서대로 전부를 돌려줍니다.
네 가지 includeIf 조건을 모두 판정해 결과를 함께 보여줍니다. gitdir: 과 gitdir/i: 는 작업 트리가 아니라 저장소의 .git 디렉터리 경로 전체를 글로브로 비교합니다. 그래서 /로 끝나는 패턴에는 /**이 붙고, ~/로 시작하면 홈 기준, ./로 시작하면 그 조건이 적힌 파일 기준이며, 그 어느 쪽도 아니면 앞에 **/이 붙습니다. gitdir:~/work 처럼 끝에 슬래시가 없으면 아무것도 걸리지 않는 이유가 이것입니다. onbranch: 는 짧은 브랜치 이름과 같은 방식으로 비교하므로 onbranch:* 는 feature/new-ui에 걸리지 않지만 onbranch:** 는 걸립니다. hasconfig:remote.*.url: 은 다른 hasconfig: 조건을 모두 참으로 두고(gitdir:와 onbranch:는 그대로 판정) 설정 전체를 한 번 훑어 답하므로, 조건보다 아래에 적힌 remote나 include가 불러온 파일의 remote도 계산에 들어갑니다.
특히 헷갈리는 두 가지도 짚어 줍니다. .git/config.worktree는 .git/config 파일 자체에 extensions.worktreeConfig가 참일 때만 읽힙니다. include로 켠 것은 소용이 없습니다. 저장소 형식은 include를 따라가지 않고 그 파일 하나만 읽어 판단하기 때문입니다. 또 git이 읽지 못하는 파일은 한 줄이 아니라 명령 전체를 실패시킵니다. 닫히지 않은 [section 머리말이나 키 이름 속의 공백 하나로 git config --list가 아무것도 출력하지 않게 되며, 이 페이지는 그런 경우 반쯤 읽은 결과를 지어내지 않고 파일과 줄 번호를 알려 줍니다. 이긴 값 옆에는 --type=bool과 --type=int로 읽었을 때의 해석도 함께 보여 줍니다. k/m/g 접미사(20m은 20971520)와, = 없이 적은 키가 불리언 참이라는 사실까지 포함해서요.
다만 명령줄은 볼 수 없습니다. git -c user.name=…이나 GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n 환경 변수는 모든 파일 범위보다 위에 있고 붙여 넣을 수도 없으므로, 여기서 나온 값과 실제 값이 다르다면 그쪽을 의심해야 합니다. 파일 시스템도 없습니다. 붙여 넣지 않은 파일을 가리키는 include.path는 추측 대신 미해결로 보고하고, gitdir: 판정은 입력한 저장소 경로만큼만 정확합니다.
자주 묻는 질문
.git/config.worktree를 만들었는데 아무 일도 일어나지 않습니다.
.git/config에 extensions.worktreeConfig가 참으로 적혀 있지 않기 때문입니다. 덜 알려진 함정은, .git/config가 include한 파일에서 켜도 소용이 없다는 점입니다. git은 저장소 형식을 판단할 때 include를 따라가지 않고 그 파일 하나만 읽기 때문에, 확장은 .git/config에 직접 적혀 있어야 합니다. git config --worktree나 git worktree가 이 일을 대신 해 주기 때문에, 손으로 만들지 않았을 때는 대개 잘 동작합니다. 문서는 core.repositoryFormatVersion을 1로 올리라고도 하지만 git 2.43은 버전이 0이어도 worktree 파일을 읽습니다. 그래서 이 페이지는 실제 동작을 그대로 재현하되, 버전이 맞지 않는 상황은 따로 표시합니다. 다른 컴퓨터의 옛 git은 무시할 수도 있으니까요.
범위를 읽는 순서는 어떻게 되고, 명령줄 설정은 어디에 있나요?
system, global, local, worktree, 그리고 명령줄 순서입니다. 이 페이지는 앞의 네 가지 파일 범위를 다룹니다. 명령줄이란 git -c key=value …, GIT_CONFIG_KEY_n과 GIT_CONFIG_VALUE_n 환경 변수 쌍, 그리고 명령 자신이 내부적으로 넘기는 옵션을 말하며, 어느 것도 붙여 넣을 수 있는 파일에 들어 있지 않습니다. git config --list --show-scope는 이것을 command line이라고 표시합니다. 여기서 나온 값과 실제 컴퓨터의 값이 다르다면 가장 먼저 볼 곳이 바로 여기입니다. GIT_CONFIG_SYSTEM, GIT_CONFIG_GLOBAL, GIT_CONFIG_NOSYSTEM은 성격이 다릅니다. 새 범위를 얹는 것이 아니라 기존 파일 범위를 바꿔치기하거나 없애 버립니다.
[remote "Origin"]과 [remote "origin"]은 같은 것인가요?
다릅니다. 그리고 이것이 리모트가 둘로 늘어나는 실제 원인입니다. 섹션 이름과 키 이름은 대소문자를 가리지 않고 git이 소문자로 출력하므로 [CORE] BigFileThreshold는 core.bigfilethreshold가 됩니다. 반면 큰따옴표로 묶인 서브섹션은 글자 그대로 비교하므로 [remote "Origin"]과 [remote "origin"]은 서로 다른 리모트이고 git remote -v에 둘 다 나옵니다. 예외는 이제 권장되지 않는 점 표기 [section.SubSection]입니다. 머리말 전체가 하나의 토큰으로 읽히면서 소문자로 접히므로 section.subsection이 되어 소문자 조회에 걸립니다. 이 페이지는 두 가지를 모두 구현하므로, 점 표기는 해석되고 따옴표 표기는 해석되지 않는 차이를 그대로 볼 수 있습니다.
includeIf "gitdir:~/work"가 전혀 걸리지 않습니다.
gitdir: 패턴은 작업 트리가 아니라 .git 디렉터리 경로와 비교되고, 접두사 비교가 아니라 경로 전체에 대한 글로브 비교입니다. 그래서 ~/work는 이름이 정확히 ~/work인 git 디렉터리에만 걸립니다. 원하는 것은 ~/work/이며, 끝의 슬래시가 ~/work/**로 확장되어 그 아래 전부를 잡습니다. 함께 외워 둘 규칙이 셋 더 있습니다. 절대 경로도 ~/도 ./도 아닌 패턴에는 앞에 **/가 붙으므로 gitdir:acme/는 디스크 어디에 있든 acme 디렉터리에 걸립니다. ./는 그 조건이 적힌 파일을 기준으로 하므로 프로젝트 폴더에 넣어 둔 .gitconfig가 그 자체로 완결됩니다. gitdir/i:는 대소문자를 무시하는 같은 비교로, macOS와 Windows에서 필요합니다.
--get은 값을 하나만 주는데 --get-all은 셋을 줍니다. 왜 그런가요?
한 키를 여러 번 설정할 수 있고 git은 읽은 순서대로 전부를 보관하기 때문입니다. --get은 그중 마지막 하나를 주며 git 대부분이 이 값을 씁니다. --get-all은 목록 전체를 줍니다. 목록이 없으면 의미가 없는 키도 있습니다. remote.origin.fetch는 보통 refspec이 둘 셋이고, safe.directory는 애초에 목록이며, include.path는 이어 붙인 파일 수만큼입니다. 그래서 git config remote.origin.fetch …로 쓰면 항목이 추가되는 것이 아니라 하나가 교체되고, --add, --replace-all, --unset-all이 따로 있는 것입니다. 이 페이지의 덮인 값 열은 밀려난 후보를 파일과 줄까지 함께 보여 주므로, 값이 교체된 것인지 나란히 쌓인 것인지 구분할 수 있습니다.
한 줄이 잘못됐다고 파일 전체를 오류라고 합니다. 그 줄만 건너뛰면 안 되나요?
git도 그렇게 하지 않습니다. 그리고 그 사실을 보여 주는 것이 이 표시의 목적입니다. 설정 파일은 하나의 스트림으로 파싱되며, 파서가 처리할 수 없는 바이트 하나 — 닫히지 않은 [section 머리말, 키 이름 속의 공백, 짝이 맞지 않는 큰따옴표, 알 수 없는 역슬래시 이스케이프 — 만으로 읽기 전체가 실패합니다. git config --list는 아무것도 출력하지 않고, 설정을 읽는 모든 명령이 똑같이 실패하며, 대개 지금 편집하던 파일과는 다른 파일 이름을 들먹입니다. 표시되는 줄 번호는 문제가 된 구문이 시작된 줄입니다. 반대로 망가져 보이지만 멀쩡한 경우도 있습니다. 섹션 머리말보다 앞에 적힌 키는 정상적으로 파싱되어 --list에 orphan처럼 나오지만, 조회에는 섹션 이름이 필요하므로 git config --get orphan은 거부됩니다. 잘못된 것이 아니라 부를 수 없는 값입니다.
관련 도구
.gitignore 테스터
.gitignore와 경로 목록을 붙여넣으면 어떤 경로가 무시되는지, 그리고 몇 번째 줄이 그렇게 결정했는지 git check-ignore -v처럼 보여줍니다.
개발
.mailmap 테스터
.mailmap과 작성자 신원 목록을 붙여 넣으면 각 신원이 무엇으로 바뀌는지, 어느 줄이 그렇게 만들었는지, 누가 하나로 합쳐지는지 보여 줍니다.
개발
Git 인덱스 검사기
.git/index를 브라우저에서 읽습니다. 스테이징된 항목의 해시·모드·플래그, 충돌 스테이지, 확장, 끝 체크섬까지 확인하세요.
파일
XPath 테스터
브라우저에서 XML이나 HTML에 XPath 식을 실행해 일치하는 모든 노드를 봅니다. 네임스페이스 접두어와 해석 오류도 함께 보고합니다.
개발
EditorConfig 테스터
.editorconfig와 파일 경로를 붙여넣으면 각 파일에 최종 적용되는 속성과, 그 값을 정한 섹션과 줄 번호를 보여줍니다.
개발
HTTP 메서드 참조
각 HTTP 메서드(GET·POST·PUT·DELETE·PATCH 등) 카드 — 안전성·idempotence·캐시 가능 여부·요청/응답 본문 허용.
개발