🧹 git 도입 + “검증 후 삭제” 원칙으로 529M → 133M
진단으로 진범(중복 백업 397M)과 근본 원인(git 부재)을 찾았다. 이제 정리할 차례. 핵심은 단순 삭제가 아니라 — 안전망을 먼저 확인하고 나서만 지운다는 순서의 설계다.
📋 이 글에서 다루는 것
- 1. 왜 git이 먼저인가 — 삭제의 전제 조건
- 2. 1단계: 소스 영구 보존 (패치 이력 포함)
- 3. 2단계: 런타임 무관 파일 삭제
- 4. 3단계: 백업 단일화 — “검증 후 삭제” 원칙
- 5. 결과 — 75% 경량화와 clean 트리
1. 왜 git이 먼저인가
검증으로 “패치를 지워도 기능은 유지된다”는 건 확인했다. 하지만 “나중에 어떤 패치가 무슨 코드를 바꿨는지 추적할 수단”은 여전히 필요하다. 파일을 그냥 지우면 그 이력이 사라진다.
git을 먼저 도입하고 패치 스크립트까지 첫 커밋에 포함시키면 — 작업 디렉토리에서 파일을 지워도 git log에 영원히 남는다. 이게 “파일 복사로 버전관리 흉내내기”를 끝내는 지점이다. 삭제의 전제 조건이 git인 이유다.
ls -la .git로 확인한 결과 버전 관리가 전무했다. 즉 지금까지 유일한 롤백 수단이 .bak 파일과 백업 디렉토리였던 것. 이걸 그냥 지웠다면 진짜로 복구 불가능한 상태가 됐을 것이다. git 없는 환경에서 백업 파일은 함부로 못 지운다 — 그게 안전망의 전부니까.
2. 1단계 — 소스 영구 보존
cd /opt/my-flashcard
git init
printf 'data/\n*.bak-*\nbackups/\ndata-backup-bc-*/\n__pycache__/\n*.pyc\n' > .gitignore
git add app.py templates/*.html Dockerfile docker-compose.yml \
requirements.txt patch_*.py migrate_base64.py
git commit -m "Phase 16 baseline: 전체 소스 + 패치 이력 보존"
처음 커밋 시 Please tell me who you are 에러가 날 수 있다. 이건 실패가 아니라 git이 작성자 정보를 요구하는 것. 로컬 전용 저장소라 실제 이메일일 필요도 없다. --global 없이 이 저장소에만 설정해 서버 전역 오염을 막는다.
git config user.email "me@flashcard.local"
git config user.name "flashcard-admin"
핵심은 패치 스크립트(patch_*.py)도 첫 커밋에 포함시켰다는 점이다. 작업 디렉토리에서 지워도 git show <commit>:patch_tags_v1.py로 언제든 꺼내 볼 수 있다. 이력이 영구 보존된다.
3. 2단계 — 런타임 무관 파일 삭제
git이 이력을 대체하므로, 이제 작업 디렉토리에서 패치/백업 파일을 지워도 진짜 안전하다.
rm -f patch_*.py migrate_base64.py
rm -f app.py.bak-* requirements.txt.bak-* templates/*.bak-*
git은 이 삭제를 “변경사항”으로 추적한다. 이것도 커밋해서 기록을 남긴다 — 첫 커밋에 패치가 보존돼 있으므로, 이 커밋은 “작업본에서 제거”를 기록하는 것이다.
git add -A
git commit -m "패치 스크립트 제거: git 이력으로 대체, 작업 디렉토리 경량화"
baseline(전체 보존) → gitignore → 청소 3개 커밋이 됐다. 패치 내용은 첫 커밋에 영원히 남아 있고, 작업 디렉토리는 가벼워졌다. “이력은 보존하되 작업 공간은 깨끗하게” — git이 존재하는 이유 그 자체다.
4. 3단계 — 백업 단일화 (검증 후 삭제 원칙)
이제 진짜 용량인 백업 디렉토리 3개(397M) 차례다. 여기서 이 작업 전체를 관통하는 원칙이 적용된다: 안전망이 멀쩡한 걸 눈으로 확인하기 전에는 원본을 절대 지우지 않는다.
mkdir -p /opt/_archive
tar czf /opt/_archive/flashcard-data-$(date +%Y%m%d).tar.gz data/
tar tzf /opt/_archive/flashcard-data-*.tar.gz | head -5
echo "tar exit code: $?" # 0이면 정상
tar 생성 → 무결성 검증 → 그제서야 원본 백업 삭제. 이 순서를 뒤집으면 “백업을 만들었다고 믿었는데 사실 깨져 있었던” 최악의 시나리오가 가능하다. 검증 단계를 건너뛰는 백업은 백업이 아니라 희망사항이다.
du -sh backups/ data-backup-bc-*/ # 지우기 직전 마지막 눈 확인
rm -rf backups/
rm -rf data-backup-bc-20260514-074031/
rm -rf data-backup-bc-20260520-005801/
docker compose restart
sleep 5 && docker compose logs --tail 15 flashcard-app # 에러 없으면 OK
du -sh /opt/my-flashcard/ # 용량 확인
git status # clean 확인
5. 결과 — 75% 경량화
| 항목 | Before | After |
|---|---|---|
| 디렉토리 용량 | 529M | 133M |
| 버전 관리 | 없음 (파일 복사) | git 3커밋, 패치 이력 보존 |
| 남은 파일 | 패치14 + 백업8 + 소스 | 실사용 6 + .git + .gitignore |
| 기능 | — | 마커 검증 완료 · 정상 기동 |
삭제 후 ls -la에 남은 것은 app.py, templates/, data/, Dockerfile, docker-compose.yml, requirements.txt, 그리고 .git/ + .gitignore — 딱 실사용 파일과 버전 관리뿐이다.
경량화의 75%는 patch 삭제가 아니라 백업 단일화에서 나왔다(390M). patch 14개 삭제는 0.5MB짜리 시각적 정리였을 뿐이다. 데이터로 이 둘을 구분해낸 게 핵심 — “지저분함”과 “무거움”은 다른 문제이고, 다른 해법이 필요했다.
그리고 git 도입으로 “백업 디렉토리 또 쌓임 → 또 청소”라는 사이클의 절반을 끊었다. 나머지 절반(데이터 백업의 자동화)은 다음 편의 주제다.
133M 중 132M가 라이브 data/이고, 그 사본은 /opt/_archive의 tar 하나뿐이다. 같은 서버, 같은 디스크. 디스크가 죽으면 라이브와 백업이 동시에 증발한다. 이건 백업이 아니라 “백업이 있다는 착각”이다. 3편에서 이 단일 장애점(SPOF)을 제거한다.
