19GB → 2GB: 디스크가 조용히 부푼 이야기
체감으로는 6GB쯤일 거라 생각했던 작업 폴더가, 어느 날 제대로 재 보니 19.66GB를 넘어 있었습니다. 코드는 거의 그대로인데 무엇이 이 공간을 다 먹었을까요. 범인은 하나같이 “다시 만들면 되는데 아무도 안 지운 것들”이었습니다. 다행히 비대화를 막는 건 어렵지 않습니다 — 무엇이 부풀었는지와 안전하게 지우는 법만 알면 됩니다. 이 글은 19.66GB를 약 2GB로 줄인 회수 런북이자, 그 과정에서 배운 한 가지 더 중요한 교훈에 대한 기록입니다.
용어부터 — 무엇이 부푸는가
섹션 제목: “용어부터 — 무엇이 부푸는가”코드는 그대로인데 20GB
섹션 제목: “코드는 그대로인데 20GB”전수조사를 해 보니 작업 폴더가 19.66GB였습니다. 정작 소스코드 자체는 그중 작은 일부였고, 나머지는 전부 재생성 가능한, 그러나 아무도 안 지운 것들이었습니다. 비대화의 3대 주범은 이랬습니다.
| 주범 | 대략 크기 | 정체 |
|---|---|---|
| 앱 빌드 산출물 | ~11GB | 모바일 앱 빌드 캐시·중간 산출물, 웹 빌드 출력. 전부 재생성 가능. |
| 방치된 worktree | ~4.6GB | AI 세션 격리용으로 자동 생성된 작업 사본들이 정리 안 되고 누적. 각자 의존성 폴더까지 보유. |
| 문서 폴더 속 별도 앱 | ~2.5GB | 참조용으로 문서 폴더에 통째로 들어간 앱의 빌드 바이너리. |
공통점이 보입니다. **전부 “지워도 코드가 안 사라지는 것”**입니다. 빌드 산출물은 다시 빌드하면 되고, 작업 사본은 다시 만들면 됩니다. 그런데 이것들이 자동으로 생기다 보니 아무도 의식적으로 정리하지 않았고, 그래서 조용히 쌓였습니다. 비대화의 본질은 “큰 걸 넣어서”가 아니라 “작은 사본이 치워지지 않고 누적되어서”입니다.
왜 6GB로 착각했나 — 비대화는 마찰 없이 자란다
섹션 제목: “왜 6GB로 착각했나 — 비대화는 마찰 없이 자란다”흥미로운 건, 19GB가 차오르는 동안 아무런 신호도 없었다는 점입니다. 디스크가 가득 찰 때까지는 경고가 뜨지 않고, 빌드는 평소처럼 돌고, 코드도 멀쩡히 작동합니다. 그래서 머릿속의 추정치(6GB)와 실제(19.66GB) 사이에 세 배가 넘는 간극이 생겼습니다.
이게 비대화의 가장 교활한 점입니다. 코드가 한 줄씩 부풀어 god 파일이 되는 것과 똑같은 구조입니다 — 어느 한 시점도 “잘못”이 아닙니다. 빌드 한 번이 산출물을 남기고, 세션 하나가 작업 사본을 남깁니다. 각각은 정상 동작입니다. 그런데 그 정상 동작의 부산물이 치워지지 않고 쌓이면, 마찰 없이 조용히 수십 GB가 됩니다.
그래서 측정이 먼저입니다. “체감”은 비대화를 절대 못 잡습니다. 폴더별 크기를 실제로 재 보는 것 — 그것만으로도 “어, 여기가 11GB였어?”라는 발견이 시작됩니다. 진단 없이 청소부터 하면, 정작 큰 덩어리는 그대로 두고 작은 것만 건드리다 끝납니다.
안전하게 지우는 법 — 함정이 하나 있다
섹션 제목: “안전하게 지우는 법 — 함정이 하나 있다”“그냥 폴더째 지우면 되지” 싶지만, 여기에 진짜 위험한 함정이 있습니다. 의존성 폴더가 **심볼릭 링크(junction)**로 다른 곳을 가리키고 있으면, 무심코 재귀 삭제(rm -rf 류)를 하다가 그 링크를 타고 들어가 원본까지 날릴 수 있습니다. 작업 사본 하나 지우려다 메인 저장소를 손상시키는 사고입니다. 디스크를 청소하려다 코드를 잃는, 가장 피하고 싶은 결말입니다.
| 위험한 방식 | 안전한 방식 |
|---|---|
| 작업 사본 폴더를 통째로 재귀 삭제. 안에 심볼릭 링크가 있으면 링크를 따라가 원본 의존성·소스까지 삭제될 수 있다. | 작업 사본은 반드시 버전관리 도구의 전용 제거 명령으로만 해제. 이 명령은 링크를 따라가지 않고 사본만 정확히 떼어 낸다. |
그래서 회수 런북은 도구를 가려 썼습니다. 대상마다 “올바른 도구”가 따로 있습니다.
| 지울 대상 | 쓰는 도구 | 왜 |
|---|---|---|
| 빌드 산출물 | 빌드 도구의 정식 clean 명령 | 무엇이 산출물인지 도구가 가장 정확히 안다 |
| 작업 사본(worktree) | 버전관리 전용 제거 명령 | 심볼릭 링크를 따라가지 않아 원본 안전 |
| (금지) 무엇이든 | 맹목적 재귀 삭제 | 링크 추종 → 원본까지 삭제 사고 위험 |
- 빌드 산출물은 각 빌드 도구의 정식 정리(clean) 명령으로 지웁니다 — 무엇이 산출물인지 도구가 제일 잘 압니다.
- **작업 사본(worktree)**은 반드시 버전관리 도구의 전용 제거 명령으로만 해제합니다 — 링크를 추종하지 않는 안전한 방식입니다.
- 지우기 전, 혹시 안 올린 변경이 남아 있으면 패치로 떠서 복구 아카이브를 먼저 만듭니다. 청소가 실수였더라도 되돌릴 수 있게.
회수 절차 (예시 순서)
섹션 제목: “회수 절차 (예시 순서)”- 실측 — 무엇이 얼마나 먹는지 폴더별 크기를 먼저 잽니다. 짐작 말고 측정.
- 아카이브 — 안 올린 변경이 있으면 패치로 백업해 둡니다(되돌릴 곳 마련).
- 도구별 삭제 — 빌드 산출물은 clean 명령, 작업 사본은 전용 제거 명령. 도구를 가려 씁니다.
- 매 삭제 후 검증 — 삭제할 때마다 “추적되던 파일이 0건 지워졌는지” 확인(아래 콜아웃).
- 재측정 — 줄어든 양을 확인하고 남은 잔여(잠긴 폴더 등)는 메모해 둡니다.
결과, 그리고 진짜 교훈
섹션 제목: “결과, 그리고 진짜 교훈”이렇게 단계별로 정리하자 19.66GB가 약 2.09GB로 줄었습니다 — 89% 회수. 잠겨 있던 잔여를 추가로 정리하니 약 1.67GB까지 내려가 총 **91.5%**가 빠졌습니다. 숫자만 보면 통쾌한 일회성 청소담이지만, 일회성 청소가 핵심은 아닙니다.
| 단계 | 크기 |
|---|---|
| 정리 전 | 19.66GB |
| 1차 정리 후 | 2.09GB |
| 추가 정리 후 | 1.67GB |
왜 이렇게까지 줄었는지 다시 보면 핵심이 분명해집니다. 19.66GB 중 소스코드가 차지한 몫은 아주 작았습니다. 90% 넘게가 “사본·캐시·중간 산출물”이었기 때문에, 그것들을 안전하게만 걷어 내면 코드는 한 줄도 안 잃고 거의 전부를 회수할 수 있었습니다. 바꿔 말하면, 비대화의 부피와 비대화의 가치는 정반대였습니다 — 가장 많은 공간을 먹은 것이 가장 안 중요한 것이었습니다.
진짜 교훈은 **“이게 쌓이는 줄도 몰랐다”**는 사실 그 자체에 있습니다. 19GB가 차오르는 동안 아무 경고도, 아무 마찰도 없었습니다. 재생성 가능한 산출물과 자동 생성된 작업 사본은 처음부터 버전관리에서 무시(gitignore)되도록 잡아 두고, 주기적으로 정리하는 절차를 두는 게 맞습니다. 한 번 부풀게 두면, 청소할 때 “지워도 되는 것”과 “지우면 안 되는 것”을 가리는 데 더 큰 위험과 시간이 듭니다.
관련 글: 〈소스코드가 비대해지는 걸 막지 못한 것〉, 〈대형 파일은 DB에 넣지 않는다〉. 전체 그림은 〈사례연구: SL.AIMS〉에 있습니다.