
.gitignore가 고장 난 줄 알았다: 이미 커밋된 파일 무시하기 & 흔한 실수들
.gitignore에 분명히 추가했는데 왜 자꾸 변경사항에 뜰까요? Git이 파일을 추적하는 원리를 클럽의 '블랙리스트'에 비유하여 설명하고, `git rm --cached`로 이미 들어온 불청객을 내보내는 방법, 대소문자 이슈, 그리고 CRLF 문제까지 완벽하게 파헤칩니다.

.gitignore에 분명히 추가했는데 왜 자꾸 변경사항에 뜰까요? Git이 파일을 추적하는 원리를 클럽의 '블랙리스트'에 비유하여 설명하고, `git rm --cached`로 이미 들어온 불청객을 내보내는 방법, 대소문자 이슈, 그리고 CRLF 문제까지 완벽하게 파헤칩니다.
AWS 콘솔 클릭질로 만든 서버가 왜 문제인지, Terraform으로 인프라를 코드로 선언하면 무엇이 달라지는지 실전 예제와 함께 정리했다.

새벽엔 낭비하고 점심엔 터지는 서버 문제 해결기. '택시 배차'와 '피자 배달' 비유로 알아보는 오토 스케일링과 서버리스의 차이, 그리고 Spot Instance를 활용한 비용 절감 꿀팁.

서버를 끄지 않고 배포하는 법. 롤링, 카나리, 블루-그린의 차이점과 실제 구축 전략. DB 마이그레이션의 난제(팽창-수축 패턴)와 AWS CodeDeploy 활용법까지 심층 분석합니다.

내 서버가 해킹당하지 않는 이유. 포트와 IP를 검사하는 '패킷 필터링'부터 AWS Security Group까지, 방화벽의 진화 과정.

저는 처음에 Git이 저를 놀리는 줄 알았습니다.
프로젝트 중간에 secret.json이라는 파일을 만들었고, 당연히 Git에 올라가면 안 되니까 .gitignore 파일에 추가했습니다.
# .gitignore
node_modules/
dist/
secret.json <-- 분명히 추가함!
그런데 git status를 치면 여전히 secret.json이 "Modified"라고 나오는 겁니다. 심지어 커밋도 됩니다.
"아니, 내가 무시하라고 했잖아! 왜 내 말을 안 들어?"
화가 나서 .gitignore 파일의 인코딩(UTF-8)도 바꿔보고, 줄바꿈도 넣어보고, 파일명에 오타가 있나 10번은 확인했습니다.
하지만 Git은 꿋꿋하게 그 파일을 추적하고 있었습니다. 마치 스토커처럼요.
이 문제를 해결한 건 Git의 작동 원리를 "클럽 블랙리스트"에 비유해서 이해한 뒤였습니다.
.gitignore는 클럽 입구에 있는 가드(Guard)가 들고 있는 출입 금지 명단(Blacklist)입니다.
규칙은 간단합니다: "이 명단에 있는 사람은 새로 들어올 수 없다(Untracked -> Tracked 불가)."
하지만 제 secret.json은? 이미 클럽 안에 들어와서 춤추고 있는 상태(Tracked)였습니다.
제가 .gitignore에 이름을 적은 건, "다음에 들어올 때 막아라"는 뜻이지, "지금 안에서 놀고 있는 사람을 쫓아내라"는 뜻이 아니었던 겁니다.
Git 입장에서는 이미 git add로 한 번이라도 추적(Tracking)을 시작한 파일은 .gitignore를 쳐다보지도 않습니다. 이미 관리 대상(Index에 등록됨)이니까요.
자, 그럼 클럽 안에서 놀고 있는 secret.json을 쫓아내야 합니다.
하지만 여기서 주의할 점이 있습니다. 파일 자체를 삭제하면 안 된다는 겁니다.
제 로컬 컴퓨터에는 그 파일이 필요하니까요. (API 키 등이 들어있을 테니 지우면 프로그램이 안 돌아갑니다.)
그래서 "Git의 감시망(Index/Staging Area)에서만" 제거해야 합니다. 이때 쓰는 주문이 바로 --cached 옵션입니다.
# 1. Git의 추적 리스트(캐시)에서만 제거 (로컬 파일은 생존)
git rm --cached secret.json
# 2. 이제 .gitignore가 효력을 발휘함
git status
# 추적되지 않음 (Untracked) 상태로 보이지만 .gitignore에 있어서 안 보임
이 명령어를 치면 Git은 "알겠어, 이제 이 파일은 내 관할이 아니야"라고 손을 떼게 됩니다.
그제서야 .gitignore 규칙이 적용되어 "무시됨" 상태가 됩니다.
node_modules 같은 거대 폴더를 실수로 올렸다면 -r (recursive) 옵션을 붙여야 합니다.
git rm -r --cached node_modules/
그리고 꼭 커밋을 해줘야 반영됩니다.
git commit -m "Stop tracking secret.json"
가끔 .gitignore를 대대적으로 수정했을 때는, 하나하나 git rm --cached 하기 귀찮습니다.
또는 DS_Store 같은 파일들이 여기저기 박혀있을 때도 있죠.
이때는 클럽의 모든 손님을 잠깐 밖으로 내보냈다가, 다시 입장시키는 방법을 씁니다.
# 1. 모든 파일의 추적을 해제 (용감하게!)
# . (점)은 현재 위치의 모든 것을 의미
git rm -r --cached .
# 2. 다시 모든 파일을 추가 (이때 .gitignore 규칙대로 필터링됨)
git add .
# 3. "gitignore 적용 완료"라고 커밋
git commit -m "Refresh .gitignore rules"
이 방법은 정말 시원합니다 (Catharsis). 꼬여있던 모든 gitignore 문제가 한방에 해결되죠.
단, 커밋 히스토리에 "모든 파일이 삭제됐다가 다시 추가된" 기록이 한 번 남을 수 있으니 주의하세요. (협업 중이라면 팀원들이 놀랄 수 있음)
.gitignore 문법은 은근히 까다롭습니다.
config.js: 현재 폴더와 하위 폴더의 모든 config.js 무시 (재귀적)/config.js: 프로젝트 루트 폴더에 있는 config.js만 무시 (하위 폴더는 무시 안 함)build: 파일 build와 폴더 build 둘 다 무시build/: 폴더 build만 무시 (추천)저는 처음에 그냥 build라고 적었는데, 소스 코드 안에 있는 변수명이나 다른 파일과 헷갈릴 수 있습니다. 폴더를 무시할 때는 확실하게 뒤에 슬래시(/)를 붙여주는 게 좋습니다.
!)"모든 .json은 무시하되, package.json은 추적하고 싶어!"
이런 경우에는 느낌표(!)를 씁니다.
*.json # 모든 json 무시
!package.json # 하지만 얘는 제외 (추적함)
중요: 순서가 생명입니다. 무시 규칙(*.json)이 먼저 나오고, 예외 규칙(!package.json)이 뒤에 나와야 합니다. 코드가 위에서 아래로 실행되는 것과 같습니다.
가끔 "나는 추가하고 싶은데 왜 자꾸 무시되지?" 싶을 때가 있습니다. 어떤 규칙 때문에 무시되는지 범인을 찾아주는 명령어가 있습니다.
git check-ignore -v ignored_file.js
# 출력: .gitignore:3:*.js ignored_file.js
(해석: .gitignore 파일의 3번째 줄에 있는 *.js 규칙 때문에 무시됨)
보통은 "추적할 것"이 기본이고 "무시할 것"을 적지만, 반대로 "다 무시하고 특정 파일만 추적"하는 전략도 있습니다.
# 1. 일단 다 무시
*
!*/
# 2. 소스 코드만 허용
!src/
!*.js
!*.css
이 방식은 실수로 이상한 파일이 올라가는 걸 원천 봉쇄합니다. 보안이 중요한 프로젝트에서 유용합니다.
이중 별표(**)의 마법:
logs/**/debug.log: 로그 폴더 안의, 그 하위 폴더의, 그 하위의 모든 debug.log를 찾으려면 **를 써야 합니다.가끔 이런 경우가 있습니다.
"서버 접속 정보가 담긴 config.js 파일이 있는데, 기본 템플릿은 커밋해야 하지만 내 로컬 비밀번호는 커밋하면 안 돼."
이럴 때 .gitignore에 넣으면 파일 자체가 사라지니 안 됩니다.
이때는 Git에게 "이 파일 변경사항은 못 본 척해"라고 명령할 수 있습니다.
# 1. 변경사항 무시 시작
git update-index --assume-unchanged config.js
# 2. 다시 추적 시작 (수정해서 커밋해야 할 때)
git update-index --no-assume-unchanged config.js
이걸 쓰면 git status를 쳐도 변경사항이 안 나옵니다. 하지만 남들이 수정한 내용은 pull 받을 때 덮어써질 수 있으니 주의해야 합니다.
사람은 실수를 합니다. .gitignore를 빼먹을 수도 있죠.
그래서 아예 커밋 버튼을 누르는 순간 검사를 해서, 비밀키나 대용량 파일이 있으면 커밋을 막아버리는 게 가장 좋습니다.
Husky라는 도구를 쓰면 됩니다.
// package.json
{
"scripts": {
"prepare": "husky install"
},
"lint-staged": {
"*.{js,ts}": [
"eslint --fix", // 코드 스타일 검사
"git add"
]
}
}
여기에 detect-secrets 같은 도구를 연동하면, AWS 키가 포함된 코드는 아예 커밋조차 안 됩니다. "소 잃고 외양간 고치기" 전에 "소 도둑을 입구 컷" 하는 거죠.
개발자라면 모든 프로젝트에 공통적으로 생기는 쓰레기 파일들이 있습니다.
맥(Mac) 유저라면 지긋지긋한 .DS_Store, VS Code 유저라면 .vscode 같은 것들이죠.
이걸 매번 프로젝트마다 .gitignore에 적는 건 노가다입니다.
내 컴퓨터 전체에 적용되는 블랙리스트를 만드세요.
# 1. 홈 디렉토리에 파일 생성
touch ~/.gitignore_global
# 2. 내용 추가 (원하는 만큼)
echo ".DS_Store" >> ~/.gitignore_global
echo "*.log" >> ~/.gitignore_global
echo ".vscode/" >> ~/.gitignore_global
echo "Desktop.ini" >> ~/.gitignore_global
# 3. Git에게 이 파일을 전역 설정으로 쓰라고 알려주기
git config --global core.excludesfile ~/.gitignore_global
이제 어떤 프로젝트를 만들든 .DS_Store는 자동으로 무시됩니다. 삶의 질이 올라갑니다.
.gitignore에 쓰면 팀원들 다 보게 됩니다.
"나만 쓰는 메모장 파일(todo.txt)을 무시하고 싶은데, .gitignore에 넣기도 좀 그렇네..."
이럴 땐 프로젝트 내부의 숨겨진 파일 .git/info/exclude를 열어서 적으세요.
이 파일은 .gitignore와 똑같이 동작하지만, Git에 커밋되지 않습니다. 완전한 나만의 비밀 무시 리스트입니다.
.gitignore와는 관련 없지만, 파일을 무시(입국 심사)할 때 자주 겪는 세 가지 문제가 더 있습니다.
components 폴더를 Components로 이름을 바꿨는데 Git이 인식을 못하나요?
Windows와 macOS는 기본적으로 파일 이름의 대소문자를 구분하지 않습니다. (Case Insensitive).
Git은 OS 설정을 따르기 때문에 폴더명 변경이 무시됩니다.
해결책: git mv 명령어를 써야 합니다.
git mv components temp
git mv temp Components
Git은 파일만 추적합니다. 빈 폴더는 아무리 만들어도 커밋할 수 없습니다.
logs/ 폴더 구조는 유지하고 싶은데 파일은 비워두고 싶다면?
해당 폴더 안에 .gitkeep이라는 이름의 빈 파일을 하나 만들어주면 됩니다. (사실 이름은 아무거나 상관없지만 관습적으로 .gitkeep을 씁니다.)
touch logs/.gitkeep
git status를 쳤는데 파일명이 \341\204\200... 처럼 나온다면?
Git이 비영어권 문자를 이스케이프 처리하고 있기 때문입니다.
git config --global core.quotepath false
또한, Windows는 줄바꿈을 CRLF(\r\n)로, Mac/Linux는 LF(\n)로 처리합니다.
협업할 때 이 차이 때문에 "파일 내용 전체가 수정됨"으로 뜨는 대참사가 일어납니다.
Git이 알아서 변환하게 설정해두세요.
# Windows
git config --global core.autocrlf true
# Mac
git config --global core.autocrlf input
.gitignore는 문지기일 뿐, 이미 들어온 놈(Tracked File)은 못 막는다. git rm --cached로 쫓아내고 다시 입국 심사를 받게 해라.