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

.gitignore에 분명히 추가했는데 왜 자꾸 변경사항에 뜰까요? Git이 파일을 추적하는 원리를 클럽의 '블랙리스트'에 비유하여 설명하고, `git rm --cached`로 이미 들어온 불청객을 내보내는 방법, 대소문자 이슈, 그리고 CRLF 문제까지 완벽하게 파헤칩니다.
서버를 끄지 않고 배포하는 법. 롤링, 카나리, 블루-그린의 차이점과 실제 구축 전략. DB 마이그레이션의 난제(팽창-수축 패턴)와 AWS CodeDeploy 활용법까지 심층 분석합니다.

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

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

왜 넷플릭스는 멀쩡한 서버를 랜덤하게 꺼버릴까요? 시스템의 약점을 찾기 위해 고의로 장애를 주입하는 카오스 엔지니어링의 철학과 실천 방법(GameDay)을 소개합니다.

저는 처음에 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로 쫓아내고 다시 입국 심사를 받게 해라.