본문 바로가기
빌드노트 검색

빌드노트

.gitignore에 넣은 설정 파일이 계속 diff에 나오는 이유

이미 추적 중인 설정 파일에는 .gitignore만 추가해도 diff가 남는다. 독립 Git 저장소에서 ignore 전후 상태와 rm --cached의 로컬 파일 보존, 일반 rm의 삭제를 비교하고 공유 기본값을 예제 파일로 남길지 판단한다.

이미 커밋한 settings.local.properties를 .gitignore에 넣었는데도 포트 값을 바꾸면 diff에 나타날 수 있다. ignore 규칙은 이미 추적 중인 파일을 추적 해제하지 않는다. 개인 설정을 저장소에서 빼려면 인덱스에서도 제거해야 한다. 다만 팀이 함께 쓰는 설정이라면, 변경이 귀찮다는 이유로 제외하기 전에 공유할 기본값과 개인 값을 나눠야 한다. Git의 gitignore 문서 (새 탭에서 열림)

패턴을 바꾸기 전에 추적 목록을 확인한다

이 동작을 확인하려고 새 독립 저장소에서 합성 설정 파일 두 개를 비교했다. settings.local.properties는 port=18080으로 커밋한 뒤 port=18081로 수정했고, new.local.properties는 port=19081로 만들고 한 번도 추가하지 않았다. 실제 프로젝트에서 생긴 사건이 아니라 Windows 11, Git 2.45.1.windows.1, PowerShell 7.6.6에서 실행한 실습이다.

저장소 루트의 .gitignore에 다음 두 줄을 넣었다. 앞의 /는 이 .gitignore가 있는 루트의 해당 경로를 가리킨다. 기존 파일에 적용할 때는 .gitignore를 통째로 덮어쓰지 않고 필요한 줄만 추가한다.

/settings.local.properties
/new.local.properties

아래 명령은 Git이 설치된 PowerShell 7에서, 해당 파일이 있는 저장소 루트에서 실행한다. 첫 명령이 출력하는 최상위 경로가 의도한 저장소인지 확인한 뒤 나머지를 실행한다. 자신의 파일명이 다르면 뒤의 경로를 바꾼다.

git rev-parse --show-toplevel
git ls-files -- settings.local.properties new.local.properties
git status --short -- settings.local.properties new.local.properties

최상위 경로를 제외한 마지막 두 명령의 실제 출력은 다음과 같았다.

settings.local.properties
 M settings.local.properties

ls-files의 기본 출력은 현재 인덱스에 등록된 파일이다. 인덱스는 다음 커밋에 넣을 내용을 준비하는 곳이다. 여기에는 여전히 settings.local.properties가 있었다. status --short의 두 번째 칸에 있는 M도 이 파일의 작업 트리 수정이 남아 있음을 보여 준다. ls-files의 기본 동작 (새 탭에서 열림), status의 두 칸 표기 (새 탭에서 열림)

반면 한 번도 추적하지 않은 new.local.properties는 ignore 전의 ?? new.local.properties 표시가 사라졌다. git status --short --ignored -- new.local.properties로 따로 확인하면 !! new.local.properties가 나왔다. 규칙은 적용됐지만 이미 추적 중인 파일의 상태를 바꾸지는 않은 것이다.

git diff -- settings.local.properties의 출력도 ignore 전후에 같았다. 삭제 줄은 -port=18080, 추가 줄은 +port=18081이었다. 이 조건에서는 ignore 패턴을 더 넓혀도 추적 상태를 해결하지 못한다. 반대로 ls-files가 비어 있다면 현재 인덱스에 없는 경로이므로, 이 사례와 같은 원인으로 단정하지 말고 작업 위치와 파일 경로, ignore 규칙을 확인한다.

--cached는 디스크의 수정본을 남긴다

이 파일을 앞으로 팀 저장소에 보관하지 않기로 정했다면, 정확한 파일 하나를 인덱스에서 뺀다. 다음 명령은 앞 실습의 .gitignore 두 줄이 있는 상태에서 이어 실행했다. 아직 포트 변경을 스테이징하지 않아 인덱스의 내용은 첫 커밋과 같았다.

git rm --cached -- settings.local.properties
git ls-files -- settings.local.properties
Test-Path -LiteralPath ./settings.local.properties -PathType Leaf
Get-Content -LiteralPath ./settings.local.properties
git status --short -- settings.local.properties
rm 'settings.local.properties'
True
port=18081
D  settings.local.properties

ls-files는 아무것도 출력하지 않았다. 이어 나온 True와 port=18081은 수정한 로컬 파일이 디스크에 그대로 남았음을 확인한 결과다. 첫 칸의 D는 다음 커밋에서 이 경로를 삭제하도록 준비했다는 뜻이다. 파일이 남아 있는데 삭제로 표시되는 것은 이 경우 정상이다. git rm의 --cached 옵션 (새 탭에서 열림)

비교용으로 만든 별도 저장소에서는 수정하지 않은 같은 이름의 파일에 git rm -- settings.local.properties를 실행했다. 이때도 상태는 D settings.local.properties였지만, Test-Path 결과는 False였다. 일반 git rm은 디스크 파일까지 지웠다. status의 D만으로 로컬 파일 보존 여부를 판단하면 안 된다.

--cached도 항상 성공하지는 않는다. 또 다른 저장소에서 HEAD에는 port=18080, 인덱스에는 port=18081, 디스크에는 port=18082를 둔 뒤 실행하자 종료 코드 1과 staged content different from both 오류가 나왔다. 인덱스가 HEAD와 디스크 양쪽 모두와 달랐기 때문이다. 파일과 인덱스 항목은 남았다. 이런 오류에서는 즉시 -f를 붙이지 말고, 스테이징한 값과 현재 파일 중 무엇을 보관할지 먼저 결정한다. 문서도 --cached 사용 시 인덱스 내용이 HEAD 또는 디스크 파일 중 하나와 일치해야 한다고 설명한다.

다음 커밋에서 빠지는 파일을 확인한다

git rm --cached는 개인 화면에서 변경 표시만 숨기는 조작이 아니다. 그 삭제를 커밋하면 새 커밋의 파일 목록에서 해당 경로가 빠진다. 팀 공통 기본값이 들어 있던 파일이라면, 이를 제거한 뒤 새로 소스를 받는 사람이 무엇으로 설정을 준비할지 정해야 한다.

이번 실습에서는 기본값 port=18080을 담은 settings.example.properties를 새로 만들었다. 이 예제 파일은 공유하고 개인 파일은 ignore하는 구성이다. Git FAQ도 기본값 또는 템플릿 파일과 수정해서 쓰는 개인 파일을 분리하는 방식을 제안한다. 다만 앱이 어떤 파일을 읽을지는 별도로 설정해야 한다. 파일명만 나눈다고 앱의 로딩 방식이 바뀌지는 않는다. 추적 중인 설정 파일에 관한 Git FAQ (새 탭에서 열림)

개인 파일의 삭제가 스테이징된 상태에서 ignore 규칙과 예제 파일을 함께 추가하고, 커밋에 들어갈 경로를 확인했다. 다음은 이 독립 저장소에서 사용한 명령이다. 실제 프로젝트에서는 기존에 스테이징한 다른 작업도 함께 표시될 수 있다. 출력 전체가 의도한 변경인지 확인한 뒤 마지막 커밋 명령을 실행한다. 앞 명령이 실패하면 그 지점에서 멈춘다.

git add -- .gitignore settings.example.properties
git diff --cached --name-status
git commit -m 'Keep local configuration out of future snapshots'

두 번째 명령의 출력은 다음과 같았다. 커밋 명령도 종료 코드 0으로 끝났다.

A	.gitignore
R100	settings.local.properties	settings.example.properties

원래 커밋된 파일과 예제 파일의 내용이 같아서 Git은 이 조합을 R100 이름 변경으로 표시했다. 이름 변경 검출이 꺼진 환경에서는 삭제와 추가가 따로 보일 수 있다. 어느 표시든 새 커밋에서 추적하는 경로는 settings.example.properties이며, 기존 개인 파일 경로는 빠진다. diff의 이름 변경 표시 (새 탭에서 열림)

커밋 뒤 로컬 파일만 port=18082로 다시 수정했다. git ls-files -- settings.local.properties와 일반 git status --short는 모두 빈 출력이었다. --ignored를 붙여 해당 경로를 조회하면 !! settings.local.properties가 나왔고 디스크의 파일은 계속 존재했다. 이제 추적 목록에서도 빠지고 ignore 규칙에도 맞는 상태다.

과거 내용까지 없어지지는 않았다. git show HEAD~1:settings.local.properties로 직전 커밋을 읽자 port=18080이 그대로 나왔다. 이번 추적 해제는 앞으로의 스냅샷을 바꿨으며 과거 커밋을 지우지 않았다.

여기서 직접 검증한 범위는 합성 파일의 추적 상태, 삭제 스테이징, 디스크 보존 여부와 로컬 커밋 전후다. 다른 팀원의 저장소에서 이 변경을 받아올 때의 동작이나 실제 앱의 설정 로딩은 시험하지 않았다. 팀이 공유해야 하는 파일이라면 추적을 유지하고 개인 설정 경로를 별도로 마련하는 쪽부터 검토한다.

← 전체 글 보기