본문으로 바로가기
Lab

gitignore 사용법, Git과 Claude Code로 직접 해 보니

새 Git 저장소에 gitignore 규칙을 넣기 전과 후를 비교했습니다. 어떤 규칙이 파일을 막았는지 확인하는 법, 이미 커밋한 파일의 추적을 끊는 법, 예외 규칙, Claude Code가 6.0초 만에 쓴 규칙까지 직접 실행한 결과로 보여 줍니다.

·

열쇠 모양 비밀 파일과 무거운 폴더는 걸러지고 코드 파일만 저장소 상자로 들어가는 그림
gitignore 사용법, Git과 Claude Code로 직접 해 보니 표지 삽화

새 저장소에 .env, node_modules/, debug.log, app.js를 만들고 git status를 실행하면 네 파일 모두 ??(아직 추적하지 않는 파일)로 표시됩니다. 여기에 gitignore 규칙 세 줄을 넣자 목록에는 app.js와 .gitignore만 남았죠. 그런데 이미 커밋한 secret.txt는 .gitignore에 적은 뒤에도 수정됨 표시 M이 그대로 떴습니다. Claude Code에게 파일 목록을 주고 규칙을 쓰게 한 마지막 단계는 6.0초가 걸렸습니다.

따라 할 순서 한눈에 보기

AI 코딩 도구로 프로젝트를 막 시작했다면 첫 커밋 전에 아래 순서를 한 번 밟아 보세요. 명령과 실제 출력은 이어지는 절에서 단계마다 보여 드립니다.

  1. 새 저장소를 만들고 git status로 올라갈 파일 목록을 먼저 확인합니다.
  2. .gitignore에 .env, node_modules/, *.log를 한 줄에 하나씩 적습니다.
  3. git check-ignore -v로 어떤 규칙이 각 파일을 막았는지 확인합니다.
  4. 이미 커밋한 파일은 .gitignore만으로는 빠지지 않으니 git rm --cached로 추적을 끊고 커밋합니다.
  5. 무시한 파일 가운데 남길 것이 있으면 !로 예외를 둡니다.
  6. Claude Code에게 폴더의 파일 목록을 주고 규칙 초안을 받은 뒤, 3번처럼 다시 확인합니다.
gitignore로 올리면 안 되는 파일 빼기 순서를 단계별로 그린 도식
이번에 따라 한 순서. .gitignore는 아직 추적하지 않는 파일에만 듣고, 이미 커밋한 파일은 git rm --cached로 추적을 끊어야 했다
도식출처: 직접 실행한 순서

그럼 규칙이 없을 때 깃이 무엇을 올리려고 하는지부터 확인해 볼까요?

함께 읽을 글

규칙을 넣기 전과 후, 무엇이 달라질까요?

빈 폴더에서 저장소를 만들고, 가짜 키를 담은 .env, 패키지 폴더, 로그 파일, 앱 코드를 차례로 만들었습니다. 작성자 정보는 --global 없이 이 저장소에만 적용했습니다.

$ git init -q -b main && git config user.name "Finn" && git config user.email "lab@solodevnote.com" && mkdir -p node_modules/lib && printf 'API_KEY=가짜값\n' > .env && printf 'console.log(1)\n' > node_modules/lib/index.js && printf '오류 기록\n' > debug.log && printf 'console.log("앱")\n' > app.js && git status --short --untracked-files=all
?? .env
?? app.js
?? debug.log
?? node_modules/lib/index.js

--untracked-files=all을 붙이면 폴더 안의 파일까지 하나하나 보여 줍니다. 이 상태에서 git add .를 하면 API 키가 든 .env도 그대로 커밋에 들어갈 수 있죠. 그래서 세 줄짜리 .gitignore를 만들었습니다.

$ printf '.env\nnode_modules/\n*.log\n' > .gitignore && cat .gitignore && git status --short --untracked-files=all
.env
node_modules/
*.log
?? .gitignore
?? app.js

.env, debug.log, node_modules/lib/index.js가 목록에서 사라졌습니다. .gitignore 파일 자체는 ??로 새로 떴는데, 이 파일은 저장소에 함께 커밋해 두는 파일입니다. 공식 설명서도 저장소를 받는 모든 사람이 무시해야 할 규칙은 .gitignore에 넣으라고 안내합니다.

파일 다섯 개가 gitignore 규칙을 넣기 전과 후에 각각 어떻게 표시됐는지 비교한 표
규칙 세 줄을 넣은 뒤 목록에는 .gitignore와 app.js만 남았습니다
도식출처: 근거를 바탕으로 코드가 그린 도식

어떤 규칙이 막았는지 확인하는 방법

규칙이 몇 줄 안 될 때는 눈으로 봐도 되지만, AI가 써 준 규칙이 길어지면 어떤 줄이 어떤 파일을 막는지 헷갈립니다. 이럴 때는 git check-ignore -v에 파일 이름을 넘겨 보세요.

$ git check-ignore -v .env debug.log node_modules/lib/index.js
.gitignore:1:.env	.env
.gitignore:3:*.log	debug.log
.gitignore:2:node_modules/	node_modules/lib/index.js

출력은 "규칙이 든 파일:줄 번호:규칙" 뒤에 막힌 경로가 붙는 모양입니다. 예를 들어 node_modules/lib/index.js는 2번째 줄의 node_modules/ 규칙에 걸렸습니다. 꼭 올라가야 할 파일이 커밋에서 빠졌다면, 이 명령으로 범인 규칙을 바로 찾을 수 있어요.

gitignore 작성법, 기호마다 뜻

규칙 문법은 gitignore 설명서와 Git 공식 책 한국어판에 나온 만큼만 정리했습니다.

쓰는 법뜻예
빈 줄, #로 시작하는 줄아무 파일과도 맞지 않음(구분선·주석)# 로그 파일
*슬래시(/)를 뺀 아무 글자*.log
?슬래시를 뺀 글자 하나?.txt
끝에 /폴더에만 맞음node_modules/, build/
끝에 /가 없음파일과 폴더 모두에 맞음node_modules
앞이나 중간에 /그 .gitignore가 있는 위치 기준으로만 맞음/TODO, doc/*.txt
/가 아예 없음그 아래 어느 폴더에서나 맞음.env
앞에 **/모든 깊이의 폴더에서 맞음**/foo
끝에 /**그 폴더 안의 모든 것(깊이 제한 없음)abc/**
가운데 /**/폴더 0개 이상doc/**/*.pdf, a/**/b
그 밖의 위치에 연속된 **일반 *처럼 취급-
앞에 !앞 규칙이 뺀 파일을 다시 포함!lib.a

공식 책 예시로 보면 /TODO는 현재 폴더의 TODO만 무시하고 subdir/TODO는 무시하지 않습니다. doc/*.txt는 doc/notes.txt는 무시하지만 doc/server/arch.txt는 무시하지 않죠. *는 슬래시를 넘지 못하기 때문입니다.

가장 간단한 방식은 최상위 폴더에 .gitignore를 하나 두는 것입니다. 그러면 모든 하위 폴더에 규칙이 적용됩니다. 무엇을 넣을지 막막하다면 공식 책이 소개하는 GitHub의 .gitignore 예제 모음을 참고할 수 있습니다. 나만 쓰는 편집기 임시 파일처럼 저장소와 공유할 필요가 없는 규칙은 $GIT_COMMON_DIR/info/exclude나 core.excludesFile로 지정한 파일에 두라고 설명서는 안내합니다.

이미 커밋한 파일은 왜 계속 추적될까요?

여기까지 따라 했다면 한 가지 궁금증이 생깁니다. 비밀 파일을 이미 커밋해 버렸다면 지금 .gitignore에 적어도 될까요? 그래서 secret.txt를 먼저 커밋한 뒤 규칙에 추가하고, 내용도 고쳐 봤습니다.

$ printf '비밀 메모\n' > secret.txt && git add . && git commit -q -m "첫 커밋" && printf 'secret.txt\n' >> .gitignore && printf '고친 비밀 메모\n' >> secret.txt && git status --short
 M .gitignore
 M secret.txt

secret.txt는 규칙에 적혀 있는데도 수정됨(M)으로 계속 잡힙니다. 설명서는 gitignore가 의도적으로 추적하지 않는 파일만 지정하며, 이미 추적 중인 파일에는 영향을 주지 않는다고 밝힙니다. 이럴 때는 git rm --cached로 추적을 끊어야 합니다.

$ git rm --cached secret.txt && git commit -q -am "secret.txt 추적 중단" && git status --short && git ls-files
rm 'secret.txt'
.gitignore
app.js

git ls-files로 본 추적 목록에는 .gitignore와 app.js만 남았습니다. 첫 커밋 때 git add .를 했는데도 .env, debug.log, node_modules/가 목록에 없다는 점도 확인되죠. 공식 책에 따르면 --cached는 디스크의 파일은 그대로 두고 깃만 추적하지 않게 합니다. 설명서는 이렇게 추적을 끊은 뒤 파일 이름을 .gitignore에 넣어 두면 이후 커밋에 다시 들어오지 않는다고 설명합니다.

다만 이 측정은 이미 만든 "첫 커밋" 안의 내용을 어떻게 처리할지는 다루지 않았습니다. 그리고 여기서는 git commit -am을 썼는데, 공식 책은 -a가 추적 중인 파일을 모두 자동으로 스테이징하므로 넣지 말아야 할 변경까지 들어갈 수 있다고 주의를 줍니다.

아직 추적하지 않는 파일, 이미 커밋한 파일, 무시하다 남길 파일, 부모 폴더가 무시된 파일별로 할 일을 비교한 표
이미 커밋한 파일은 규칙만으로 빠지지 않고, 부모 폴더가 무시된 파일은 예외 규칙이 듣지 않습니다
도식출처: 근거를 바탕으로 코드가 그린 도식

무시한 파일 중 하나만 남기고 싶다면?

*.log로 로그를 모두 막았지만 important.log 하나는 커밋하고 싶다고 해 보죠. 이때는 !로 시작하는 규칙을 뒤에 덧붙입니다.

$ printf '!important.log\n' >> .gitignore && printf '남길 기록\n' > important.log && git status --short
 M .gitignore
?? important.log

important.log가 ??로 다시 보입니다. 설명서에 따르면 같은 수준의 규칙 안에서는 마지막으로 맞은 규칙이 결과를 정합니다. 그래서 예외 규칙은 막는 규칙보다 아래에 적어야 합니다.

그런데 한계도 있습니다. 파일의 부모 폴더가 무시되면 그 안의 파일은 !로 되살릴 수 없습니다. 깃이 성능 때문에 무시된 폴더 안을 들여다보지 않기 때문이죠. 예를 들어 node_modules/를 폴더째 막았다면 그 안의 파일 하나에 !를 붙여도 효과가 없습니다. 특정 폴더만 남기려면 설명서의 예시처럼 /*로 내용물을 막고 폴더를 단계별로 되살려야 합니다.

    $ cat .gitignore
    # exclude everything except directory foo/bar
    /*
    !/foo
    /foo/*
    !/foo/bar

Claude Code에게 규칙을 맡길 때 확인할 점

규칙을 직접 쓰기 번거롭다면 AI에게 맡길 수도 있습니다. 파일·폴더 이름 목록을 파이프로 넘기고 --model opus로 규칙만 출력하게 했습니다.

$ printf '%s\n' .env .env.local node_modules dist .DS_Store npm-debug.log coverage src package.json README.md | claude --model opus -p "아래는 Node.js 프로젝트 폴더의 파일과 폴더 이름이다. 깃에 올리면 안 되는 것만 .gitignore 규칙으로 한 줄에 하나씩 출력해. 설명이나 코드 블록 표시는 붙이지 마."
.env
.env.local
node_modules
dist
.DS_Store
npm-debug.log
coverage

이번 실행에서는 src, package.json, README.md를 빼고 나머지를 규칙으로 돌려줬습니다. 눈여겨볼 점은 node_modules가 끝 슬래시 없이 나왔다는 것입니다. 앞의 표대로라면 이 규칙은 폴더뿐 아니라 같은 이름의 파일에도 맞습니다. 로그와 환경 파일도 *.log 같은 패턴이 아니라 받은 이름 그대로 적었죠.

그렇다면 AI 규칙을 그대로 붙여 넣어도 될까요? 이 출력은 한 번 실행한 결과일 뿐이고, 같은 요청이라도 실행마다 달라질 수 있습니다. 받은 규칙을 .gitignore에 넣었다면 git status --short --untracked-files=all과 git check-ignore -v로 직접 확인하는 편이 안전합니다. 특히 소스 폴더처럼 꼭 올라가야 할 파일이 걸리지 않았는지가 중요합니다.

파일 이름 카드들이 체를 지나며 커밋할 쪽과 무시할 쪽으로 나뉘는 개념 그림
gitignore 규칙이 파일 목록을 커밋할 것과 무시할 것으로 나누는 모습을 그린 개념 그림입니다

자주 하는 실수와 마지막 점검

앞의 단계에서 실제로 걸렸던 지점을 실수 목록으로 묶으면 이렇습니다.

  • 먼저 커밋하고 나중에 규칙을 추가하는 경우: 이미 추적 중인 파일은 계속 올라가니 git rm --cached가 따로 필요합니다.
  • 예외 규칙 !를 막는 규칙보다 위에 적는 경우: 마지막으로 맞은 규칙이 이깁니다.
  • 폴더째 무시한 뒤 안쪽 파일을 !로 살리려는 경우: 부모 폴더가 무시되면 되살릴 수 없습니다.
  • git commit -a를 습관처럼 쓰는 경우: 추적 중인 파일의 변경이 모두 들어갑니다.
  • AI가 쓴 규칙을 확인 없이 쓰는 경우: 실행마다 결과가 다를 수 있습니다.

첫 커밋 전에는 아래 항목을 확인해 보세요.

  • git status --short --untracked-files=all 목록에 .env나 로그 파일이 없는가
  • git check-ignore -v로 본 규칙이 의도한 줄과 일치하는가
  • git ls-files에 비밀 파일이 남아 있지 않은가
  • .gitignore 파일 자체가 커밋 대상에 들어 있는가

측정 조건과 한계

모든 단계는 맥 한 대(darwin arm64)에서 원격 저장소 없이 새 로컬 폴더 하나로 실행했습니다. 환경은 git version 2.54.0, Claude Code 2.1.309, Node.js v22.23.1입니다. .env에는 가짜 값만 넣었고, Claude Code는 이미 로그인된 상태였습니다.

명령은 단계마다 한 번씩만 실행했습니다. 1~7단계는 모두 0.0초, Claude Code 단계는 6.0초로 기록됐는데, 한 번 잰 값이라 다시 실행하면 시간과 AI의 출력 모두 달라질 수 있습니다. 윈도나 리눅스, 하위 폴더에 .gitignore를 여러 개 두는 경우, 이미 커밋된 기록을 지우는 작업은 이번 측정에 포함되지 않았습니다.

참고 자료