티스토리 뷰

.gitignore에 분명히 추가했는데도 파일이 계속 변경 목록에 뜨는 경우가 있다. 오타를 의심하고 경로를 몇 번씩 확인하게 되는데, 열에 아홉은 문법 문제가 아니다.

원인: gitignore는 "이미 추적 중인 파일"에는 안 먹는다

이게 핵심이다. .gitignore아직 Git이 모르는 파일을 무시하라는 규칙이다. 한 번이라도 git add 된 파일은 이미 인덱스(스테이징 영역)에 등록돼 있고, 그 뒤에 gitignore에 추가해봐야 Git은 계속 추적한다.

그래서 순서가 이렇게 꼬인 경우에 문제가 생긴다.

  • 프로젝트를 만들고 git add . 로 전부 커밋
  • 나중에 .envnode_modules가 들어간 걸 발견
  • .gitignore에 추가
  • 여전히 변경 목록에 뜸

해결: 인덱스에서 캐시를 걷어낸다

git rm -r --cached .
git add .
git commit -m "fix: apply gitignore"

--cached 옵션이 중요하다. 이건 인덱스에서만 제거하고 실제 파일은 건드리지 않는다. 이 옵션을 빼면 디스크에서 파일이 진짜 지워지니 절대 빠뜨리면 안 된다.

세 줄을 실행하면 Git이 추적 목록을 전부 비웠다가 다시 채우는데, 이때 .gitignore 규칙이 적용되면서 무시 대상이 빠진다.

전체가 아니라 특정 파일만 빼고 싶다면

위 명령은 전체를 다시 스테이징하기 때문에 작업 중이던 변경사항까지 같이 올라간다. 대상이 명확하면 그 파일만 지정하는 게 안전하다.

# 파일 하나
git rm --cached .env

# 디렉터리
git rm -r --cached node_modules

# 패턴
git rm --cached "*.log"

그래도 안 되면: 어느 규칙이 걸리는지 확인

규칙 자체가 잘못됐을 수도 있다. Git에는 이걸 알려주는 명령이 있다.

git check-ignore -v config/database.php

무시되고 있다면 어느 파일 몇 번째 줄의 어떤 규칙 때문인지 출력된다. 아무것도 안 나오면 그 파일은 무시 대상이 아니라는 뜻이니, gitignore 패턴을 다시 봐야 한다.

자주 걸리는 gitignore 문법 함정

1. 디렉터리를 통째로 무시하면 안쪽 예외가 안 먹는다

# 이렇게 하면 !storage/logs/.gitkeep 이 무시된다
storage/
!storage/logs/.gitkeep

# 이렇게 해야 예외가 동작한다
storage/*
!storage/logs
storage/logs/*
!storage/logs/.gitkeep

Git은 디렉터리 자체를 제외하면 그 안을 아예 들여다보지 않는다. 그래서 하위 항목을 !로 되살릴 수 없다. 상위 디렉터리를 /* 로 열어두고 단계별로 내려가야 한다.

2. 슬래시 위치에 따라 의미가 다르다

  • build : 어느 depth에 있든 이름이 build인 파일·디렉터리 전부
  • /build : 저장소 루트의 build만
  • build/ : 디렉터리만 (같은 이름의 파일은 무시 안 함)

3. 빈 디렉터리는 Git이 추적하지 않는다

로그 디렉터리 구조만 유지하고 싶으면 안에 .gitkeep 같은 빈 파일을 하나 넣고 그것만 예외 처리해야 한다.

이미 push된 민감 정보라면 이야기가 다르다

.env나 API 키가 이미 원격 저장소에 올라갔다면, git rm --cached 로는 부족하다. 그건 "앞으로 추적하지 않겠다"는 뜻일 뿐, 과거 커밋 히스토리에는 그대로 남아 있다. 누구든 이전 커밋을 체크아웃하면 볼 수 있다.

이 경우 해야 할 일은 두 가지다.

  • 키를 즉시 폐기하고 재발급한다. 이게 1순위다. 히스토리 정리보다 먼저다.
  • 히스토리에서 제거하려면 git filter-repo 또는 BFG Repo-Cleaner를 쓴다. 다만 커밋 해시가 전부 바뀌므로 협업 중인 저장소라면 팀원 전체가 다시 클론해야 한다.

공개 저장소에 올라간 키는 봇이 몇 분 안에 수집해간다고 보는 게 안전하다. 히스토리를 아무리 깔끔하게 지워도 이미 긁혔을 가능성이 있으니 재발급이 먼저다.

예방: 전역 gitignore 설정

.DS_Store, Thumbs.db, IDE 설정 폴더처럼 프로젝트와 무관하게 매번 걸리는 것들은 전역으로 빼두면 편하다.

git config --global core.excludesfile ~/.gitignore_global

# ~/.gitignore_global
.DS_Store
Thumbs.db
.idea/
.vscode/
*.swp

프로젝트 .gitignore.idea/ 같은 개인 환경 설정을 넣는 건 사실 다른 팀원 입장에서 불필요한 항목이다. 전역으로 빼두는 쪽이 협업할 때 깔끔하다.

정리

  • 적용 안 되는 이유 대부분은 이미 추적 중인 파일이기 때문이다
  • git rm -r --cached . 후 다시 add·commit (--cached 빠뜨리면 파일이 삭제된다)
  • 규칙이 의심되면 git check-ignore -v 로 확인
  • 디렉터리 전체 제외 시 하위 예외(!)는 안 먹는다. /* 로 단계별 처리
  • 이미 push된 비밀키는 재발급이 먼저, 히스토리 정리는 그다음
댓글


최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday