TL;DR: .gitignore가 안 먹힌다면 십중팔구 파일이 이미 트래킹 중입니다. Git은 한 번도 본 적 없는 파일만 무시합니다 — 인덱스에 들어 있는 파일은 어떤 규칙도 뚫지 못합니다. git check-ignore -v <path>로 진실을 확인하세요: 출력이 없으면 그 경로는 트래킹 중이고 규칙이 적용되지 않는다는 뜻입니다. git rm --cached <path>로 고치고 커밋하면, 그 커밋부터 무시 규칙이 동작합니다. 규칙 순서, 부정(negation) 함정, VS Code 미끼가 나머지 경우를 설명합니다.
.gitignore가 왜 안 먹히나?
사례의 대다수를 한 가지 메커니즘이 커버합니다: 규칙이 생기기 전에 파일이 이미 커밋돼 있었다. .gitignore는 git에게 파일을 숨기는 필터가 아닙니다 — 언트래킹 상태에서 git add가 무엇을 집어 올릴지 정하는 규칙입니다. 일단 인덱스에 들어온 파일은 git이 직접 언트래킹하기 전까지 영원히 내용 변경을 추적합니다. 사후에 .gitignore를 고쳐 봐야 트래킹 중인 파일에는 아무 효과가 없습니다. 그래서 “.env 커밋, 패닉, .gitignore에 .env 추가, 다시 커밋”의 고전적 시퀀스가 push할 때마다 여전히 시크릿을 실어 보내는 것입니다.
이 문제가 모두를 물고 다니는 이유는 git의 보급 때문입니다 — Stack Overflow 2022 설문이 전문 개발자의 93% 이상이 Git을 쓴다고 잡았고(survey.stackoverflow.co), 그 개발자들 모두 언젠가 지난주에 커밋한 파일에 규칙을 씁니다.
이 글의 나머지는 소수 사례입니다: 규칙 순서 실수, 부정 함정, 폴더 엣지 케이스, IDE 문제. 하지만 다음 섹션의 건강 검진을 먼저 돌리세요 — 열 번 중 아홉 번 이상은 조사가 거기서 끝납니다.
어떤 gitignore 규칙이 파일에 매칭되는지 확인하려면?
git check-ignore가 진단 도구이고, 이 도구의 침묵이 곧 진단입니다:
# 규칙이 적용될 때: 매칭된 규칙 + 파일 + 줄 번호를 출력
git check-ignore -v debug.log
# .gitignore:3:*.log debug.log
# 규칙이 적용되지 않으면 아무것도 출력하지 않음 — 파일이 트래킹 중(또는 규칙이 없음)
git check-ignore -v src/.env
# (침묵 = .gitignore가 이 경로를 무시하지 않는다, 뭘 썼든 간에)
# 종료 코드: 0 = 무시됨, 1 = 무시 안 됨 — 스크립트 가능
git check-ignore -q debug.log && echo "ignored" || echo "tracked or unruly" -v 출력 읽는 법: 무시 소스(.gitignore, .git/info/exclude, 또는 전역 무시 파일), 이어서 줄번호:패턴, 이어서 경로. 뒤의 규칙이 놀라움을 준다면 우선순위를 기억하세요: 마지막으로 매칭된 규칙이 이깁니다, 그래서 *.log 뒤의 !important.log가 그 파일 하나만 다시 포함합니다.
이미 커밋된 파일에는 gitignore가 왜 안 먹히나?
파일을 언트래킹하고, 디스크에는 남기고, 제거를 커밋하세요:
# 파일 하나 언트래킹 (로컬 사본은 살아남는다 — --cached는 인덱스만 건드린다)
git rm --cached .env
git commit -m "stop tracking .env"
# 무시 규칙이 이제 적용되는지 확인
git check-ignore -v .env 이 커밋부터 .gitignore가 그 경로를 소유합니다: 파일을 수정해도 git status에 나오지 않고, git add .가 다시 집어 올리지도 않습니다. 다만 파일은 히스토리에 남아 있습니다 — 시크릿이었다면 최신 커밋에서 제거하는 것으로는 부족합니다. 크리덴셜을 로테이션하는 것만이 진짜 해결이고, 히스토리 재작성은 화장뿐입니다(마지막 커밋 되돌리기는 나쁜 커밋이 아직 꼭대기일 때만 도움이 됩니다).
예전에 커밋된 잡동사니가 가득한 저장소 — 빌드 산출물, 에디터 찌꺼기, 일찍 들어와 버린 node_modules — 에는 대량 언트래킹이 두 줄이면 끝납니다:
git rm -r --cached .
git add .
git commit -m "apply .gitignore to tracked files" 인덱스를 현재 규칙 기준으로 다시 빌드하는 것입니다: 무시되는 경로는 빠지고, 나머지는 그대로 다시 들어갑니다. diff는 극적으로 보입니다(수천 개의 삭제)만 디스크에서는 아무것도 지우지 않습니다. 언트래킹이 아니라 파일 삭제 자체가 목적이라면 그건 git clean -fdx의 영역입니다 — git remove untracked files, safely를 보세요.
Git은 한 번도 본 적 없는 파일만 무시합니다. 이미 인덱스에 들어 있는 파일은
.gitignore가 손도 쓸 수 없습니다 — 어떤 규칙을 써도 잊어주지 않습니다.
폴더에는 gitignore가 왜 안 먹히나?
폴더 고유의 함정 셋:
1. 뒤에 붙는 슬래시는 의도의 표시이지 매칭 조건이 아니다. build와 build/는 둘 다 디렉터리에 매칭되지만, build/는 디렉터리만 지정한다는 문서화입니다 — build라는 이름의 파일은 살아남습니다. 다만 재포함에서는 이 대칭이 깨집니다(다음 함정).
2. 부정은 제외된 디렉터리 안의 파일을 구하지 못한다. git 문서가 단호합니다: “파일의 상위 디렉터리가 제외되어 있으면 그 파일을 다시 포함할 수 없다”(git-scm.com/docs/gitignore). 성능 결정입니다 — git은 제외된 디렉터리를 통째로 건너뛰고 그 안을 들여다보지 않습니다. 따라서 이건 동작하지 않습니다:
build/
!build/keep.me # 죽은 규칙 — git은 build/ 안을 아예 안 본다 해결은 디렉터리가 아니라 내용물을 제외하는 것입니다:
build/*
!build/keep.me # 동작 — build/ 자체는 여전히 들여다볼 수 있으므로 3. 중첩된 .gitignore가 자기 범위에서 이긴다. subdir/.gitignore의 규칙은 subdir 아래 경로에서 루트 파일을 덮어씁니다. git check-ignore -v가 예상 밖의 무시 소스를 지목할 때가 바로 이 경우입니다.
VS Code에서는 gitignore가 왜 안 먹히나?
VS Code 탓인 경우는 거의 없습니다. 에디터의 소스 컨트롤 뷰는 git과 같은 인덱스를 읽으므로 증상이 동일합니다: 파일이 이미 커밋돼 있었고, IDE 재시작으로는 인덱스가 바뀌지 않습니다. 알아둘 만한 VS Code 인근의 사실 둘:
- 익스플로러에서 회색 = 무시됨; 주황/노랑 = 트래킹 중이며 변경 있음. 무시한 다음에도 수정됨으로 표시되는 파일은 트래킹 중이라는 확인입니다 — 위의
git rm --cached해결법을 실행하세요. - 익스플로러의 변경 목록에
.gitignore가 안 보이면 규칙이 동작하는 겁니다 — 애초에 언트래킹 파일로 나타나지 않는 것입니다. 사람들은 CLIgit status와 낡은 SCM 뷰가 어긋났을 때 “VS Code가 내 gitignore를 무시한다”고 보고하곤 합니다; git 탓하기 전에 창을 새로 고치세요(Cmd/Ctrl+Shift+P→ “Reload Window”).
.gitignore vs .git/info/exclude vs global: 언제 무엇을 쓰나
| 파일 | 범위 | 커밋되나? | 용도 |
|---|---|---|---|
.gitignore (저장소) | 클론하는 모든 사람 | 예 | 빌드 산출물, 의존성, .env — 공유 규칙 |
.git/info/exclude | 내 클론만 | 아니요 | 개인 잡동사니: .scratch/, 에디터 찌꺼기 |
core.excludesFile (전역) | 내 모든 저장소 | 아니요 | OS 잡동사니: .DS_Store, Thumbs.db, *.swp |
.gitignore + 부정 | 저장소 | 예 | 트래킹된 설정의 예외 재포함 |
전역 파일이 개발자들이 가장 설정하지 않으면서도 설정해야 할 파일입니다:
git config --global core.excludesFile ~/.gitignore_global
printf '.DS_Store\nThumbs.db\n*.swp\n' >> ~/.gitignore_global 가져다 쓸 만한 하우스 룰: 팀 전체에 이득이 되는 규칙은 저장소로, 나만 이득인 규칙은 exclude나 전역 파일로. 개인 무시 규칙을 커밋하는 것이 .gitignore를 300줄짜리로 부풀려 어느 절반이 아직 유효한지 아무도 모르게 만드는 길입니다.
트래킹된 파일의 변경은 어떻게 무시하나?
트래킹된 파일(설정 템플릿, IDE 설정 파일)을 유지하면서 로컬 수정만 git status에 안 나오게 하고 싶을 때가 있습니다. git update-index의 플래그 두 개, 둘 다 팀 워크플로에는 속하지 않습니다:
git update-index --skip-worktree config/local.dev # 로컬 수정이 조용해진다
git update-index --no-skip-worktree config/local.dev # ...그리고 되돌린다 --skip-worktree가 정당화 가능한 쪽입니다 — “내 로컬 버전은 의도적으로 갈라졌다”는 뜻입니다. 사촌 --assume-unchanged는 성능 약속(“이 파일은 안 바뀔 것이다”)이지 무시 메커니즘이 아니며, git이 조용히 어긋나게 만들 수 있습니다. 두 플래그 모두 업스트림도 파일을 바꾼 상태로 pull하면 요란하게 실패합니다 — 오래가는 답은 만드는 시점부터 exclude로 로컬 전용 설정을 두거나, git이 트래킹하는 템플릿 파일(config.example)을 복사해 쓰는 것입니다.
30초 gitignore 건강 검진
git check-ignore -v <path> # 어떤 규칙? (침묵 = 트래킹 중, 규칙 없음)
git ls-files --error-unmatch <path> # 애초에 트래킹 중인가?
git rm --cached <path> # 언트래킹, 디스크는 유지
git commit -m "stop tracking <path>"
git check-ignore -v <path> # 이제 규칙이 보인다 진단하고, 언트래킹하고, 검증합니다. 모든 “gitignore not working” 보고의 배후에는 같은 패턴이 있습니다 — 인덱스의 한쪽 면에서는 트래킹되고 다른 면에서는 무시되는, 두 개의 모자를 쓴 하나의 파일 — 그리고 --cached 플래그 하나가 두 번째 모자를 벗겨 줍니다.
FAQ
.gitignore가 왜 안 먹히나요?
대부분 파일이 이미 트래킹 중이기 때문입니다. Git은 언트래킹된 파일만 무시하며, 인덱스에 들어 있는 파일은 git rm --cached로 언트래킹해 커밋하기 전까지 .gitignore의 영향을 받지 않습니다.
어떤 gitignore 규칙이 파일에 매칭되는지 확인하려면?
git check-ignore -v <path>를 실행하세요. 정확한 .gitignore 줄과 규칙 번호를 출력하고, 파일이 트래킹 중이어서 규칙이 적용되지 않으면 조용히 종료합니다.
git rm --cached가 로컬 파일을 삭제하나요?
아니요. --cached는 인덱스에서만 파일을 제거하고 디스크의 사본은 그대로 둡니다. 제거를 커밋하면 파일은 언트래킹 상태가 되고, 그다음부터 .gitignore가 적용됩니다.
gitignore는 무시된 폴더 안의 파일을 다시 포함할 수 없나요?
Git은 성능상 제외된 디렉터리를 아예 건너뜁니다. git 문서에도 파일의 상위 디렉터리가 제외되어 있으면 그 파일을 다시 포함할 수 없다고 명시돼 있습니다.
— mrsaynothing
Get the next one by email
One email per post. No spam, no algorithms.
what is this?Ollama가 GPU를 안 쓴다면? Linux·Windows·WSL에서 고치기
글이 마음에 드셨나요? 제 본업이 바로 이런 일입니다. 저를 고용하세요