콘텐츠로 이동

19GB → 2GB: 디스크가 조용히 부푼 이야기

체감으로는 6GB쯤일 거라 생각했던 작업 폴더가, 어느 날 제대로 재 보니 19.66GB를 넘어 있었습니다. 코드는 거의 그대로인데 무엇이 이 공간을 다 먹었을까요. 범인은 하나같이 “다시 만들면 되는데 아무도 안 지운 것들”이었습니다. 다행히 비대화를 막는 건 어렵지 않습니다 — 무엇이 부풀었는지안전하게 지우는 법만 알면 됩니다. 이 글은 19.66GB를 약 2GB로 줄인 회수 런북이자, 그 과정에서 배운 한 가지 더 중요한 교훈에 대한 기록입니다.

전수조사를 해 보니 작업 폴더가 19.66GB였습니다. 정작 소스코드 자체는 그중 작은 일부였고, 나머지는 전부 재생성 가능한, 그러나 아무도 안 지운 것들이었습니다. 비대화의 3대 주범은 이랬습니다.

주범대략 크기정체
앱 빌드 산출물~11GB모바일 앱 빌드 캐시·중간 산출물, 웹 빌드 출력. 전부 재생성 가능.
방치된 worktree~4.6GBAI 세션 격리용으로 자동 생성된 작업 사본들이 정리 안 되고 누적. 각자 의존성 폴더까지 보유.
문서 폴더 속 별도 앱~2.5GB참조용으로 문서 폴더에 통째로 들어간 앱의 빌드 바이너리.
19.66GB는 무엇으로 차 있었나 빌드 산출물 ~11GB worktree ~4.6 문서앱 코드 0GB 19.66GB → 빨강·주황·보라(약 18GB)는 전부 "지워도 코드가 안 사라지는 것" 정리 후 ≈ 2.09GB — 약 89% 회수 (추가 정리로 1.67GB, 총 91.5%) 소스코드는 거의 그대로. 부푼 건 전부 사본·캐시·중간 산출물이었다.
19.66GB의 구성: 막대의 거의 전부가 재생성 가능한 산출물·작업 사본입니다. 그래서 안전하게만 지우면 90% 넘게 회수됩니다 — 코드는 한 줄도 안 잃고.

공통점이 보입니다. **전부 “지워도 코드가 안 사라지는 것”**입니다. 빌드 산출물은 다시 빌드하면 되고, 작업 사본은 다시 만들면 됩니다. 그런데 이것들이 자동으로 생기다 보니 아무도 의식적으로 정리하지 않았고, 그래서 조용히 쌓였습니다. 비대화의 본질은 “큰 걸 넣어서”가 아니라 “작은 사본이 치워지지 않고 누적되어서”입니다.

왜 6GB로 착각했나 — 비대화는 마찰 없이 자란다

섹션 제목: “왜 6GB로 착각했나 — 비대화는 마찰 없이 자란다”

흥미로운 건, 19GB가 차오르는 동안 아무런 신호도 없었다는 점입니다. 디스크가 가득 찰 때까지는 경고가 뜨지 않고, 빌드는 평소처럼 돌고, 코드도 멀쩡히 작동합니다. 그래서 머릿속의 추정치(6GB)와 실제(19.66GB) 사이에 세 배가 넘는 간극이 생겼습니다.

이게 비대화의 가장 교활한 점입니다. 코드가 한 줄씩 부풀어 god 파일이 되는 것과 똑같은 구조입니다 — 어느 한 시점도 “잘못”이 아닙니다. 빌드 한 번이 산출물을 남기고, 세션 하나가 작업 사본을 남깁니다. 각각은 정상 동작입니다. 그런데 그 정상 동작의 부산물이 치워지지 않고 쌓이면, 마찰 없이 조용히 수십 GB가 됩니다.

그래서 측정이 먼저입니다. “체감”은 비대화를 절대 못 잡습니다. 폴더별 크기를 실제로 재 보는 것 — 그것만으로도 “어, 여기가 11GB였어?”라는 발견이 시작됩니다. 진단 없이 청소부터 하면, 정작 큰 덩어리는 그대로 두고 작은 것만 건드리다 끝납니다.

안전하게 지우는 법 — 함정이 하나 있다

섹션 제목: “안전하게 지우는 법 — 함정이 하나 있다”

“그냥 폴더째 지우면 되지” 싶지만, 여기에 진짜 위험한 함정이 있습니다. 의존성 폴더가 **심볼릭 링크(junction)**로 다른 곳을 가리키고 있으면, 무심코 재귀 삭제(rm -rf 류)를 하다가 그 링크를 타고 들어가 원본까지 날릴 수 있습니다. 작업 사본 하나 지우려다 메인 저장소를 손상시키는 사고입니다. 디스크를 청소하려다 코드를 잃는, 가장 피하고 싶은 결말입니다.

위험한 방식안전한 방식
작업 사본 폴더를 통째로 재귀 삭제. 안에 심볼릭 링크가 있으면 링크를 따라가 원본 의존성·소스까지 삭제될 수 있다.작업 사본은 반드시 버전관리 도구의 전용 제거 명령으로만 해제. 이 명령은 링크를 따라가지 않고 사본만 정확히 떼어 낸다.

그래서 회수 런북은 도구를 가려 썼습니다. 대상마다 “올바른 도구”가 따로 있습니다.

지울 대상쓰는 도구
빌드 산출물빌드 도구의 정식 clean 명령무엇이 산출물인지 도구가 가장 정확히 안다
작업 사본(worktree)버전관리 전용 제거 명령심볼릭 링크를 따라가지 않아 원본 안전
(금지) 무엇이든맹목적 재귀 삭제링크 추종 → 원본까지 삭제 사고 위험
  • 빌드 산출물은 각 빌드 도구의 정식 정리(clean) 명령으로 지웁니다 — 무엇이 산출물인지 도구가 제일 잘 압니다.
  • **작업 사본(worktree)**은 반드시 버전관리 도구의 전용 제거 명령으로만 해제합니다 — 링크를 추종하지 않는 안전한 방식입니다.
  • 지우기 전, 혹시 안 올린 변경이 남아 있으면 패치로 떠서 복구 아카이브를 먼저 만듭니다. 청소가 실수였더라도 되돌릴 수 있게.
  1. 실측 — 무엇이 얼마나 먹는지 폴더별 크기를 먼저 잽니다. 짐작 말고 측정.
  2. 아카이브 — 안 올린 변경이 있으면 패치로 백업해 둡니다(되돌릴 곳 마련).
  3. 도구별 삭제 — 빌드 산출물은 clean 명령, 작업 사본은 전용 제거 명령. 도구를 가려 씁니다.
  4. 매 삭제 후 검증 — 삭제할 때마다 “추적되던 파일이 0건 지워졌는지” 확인(아래 콜아웃).
  5. 재측정 — 줄어든 양을 확인하고 남은 잔여(잠긴 폴더 등)는 메모해 둡니다.

이렇게 단계별로 정리하자 19.66GB가 약 2.09GB로 줄었습니다 — 89% 회수. 잠겨 있던 잔여를 추가로 정리하니 약 1.67GB까지 내려가 총 **91.5%**가 빠졌습니다. 숫자만 보면 통쾌한 일회성 청소담이지만, 일회성 청소가 핵심은 아닙니다.

단계크기
정리 전19.66GB
1차 정리 후2.09GB
추가 정리 후1.67GB

왜 이렇게까지 줄었는지 다시 보면 핵심이 분명해집니다. 19.66GB 중 소스코드가 차지한 몫은 아주 작았습니다. 90% 넘게가 “사본·캐시·중간 산출물”이었기 때문에, 그것들을 안전하게만 걷어 내면 코드는 한 줄도 안 잃고 거의 전부를 회수할 수 있었습니다. 바꿔 말하면, 비대화의 부피와 비대화의 가치는 정반대였습니다 — 가장 많은 공간을 먹은 것이 가장 안 중요한 것이었습니다.

진짜 교훈은 **“이게 쌓이는 줄도 몰랐다”**는 사실 그 자체에 있습니다. 19GB가 차오르는 동안 아무 경고도, 아무 마찰도 없었습니다. 재생성 가능한 산출물과 자동 생성된 작업 사본은 처음부터 버전관리에서 무시(gitignore)되도록 잡아 두고, 주기적으로 정리하는 절차를 두는 게 맞습니다. 한 번 부풀게 두면, 청소할 때 “지워도 되는 것”과 “지우면 안 되는 것”을 가리는 데 더 큰 위험과 시간이 듭니다.


관련 글: 〈소스코드가 비대해지는 걸 막지 못한 것〉, 〈대형 파일은 DB에 넣지 않는다〉. 전체 그림은 〈사례연구: SL.AIMS〉에 있습니다.