Git 히스토리의 대용량 파일 제거 — filter-repo

기초·개념2분조회

이미 커밋 히스토리에 들어간 대용량 파일은 워킹 디렉토리에서 지운다고 사라지지 않고, 히스토리 자체를 다시 써야 없앨 수 있습니다. git filter-repo 는 그 히스토리를 통째로 재작성하는 공식 도구입니다.

백업 JSON 을 실수로 커밋하고 push 했더니 GitHub 이 막았습니다.

remote: error: File AWS/s3/2024_back_log.json is 2343.67 MB;
  this exceeds GitHub's file size limit of 100.00 MB
remote: error: GH001: Large files detected.

.gitignore로는 못 지우는 이유

먼저 .gitignore 에 그 파일을 넣어봤지만 소용없었습니다. .gitignore아직 추적 안 하는 파일을 앞으로 안 넣겠다는 것이지, 이미 커밋 히스토리에 들어간 파일을 지우지 않습니다.

GitHub 은 push 되는 커밋들의 히스토리 전체를 봅니다. 지금 워킹 디렉토리에서 파일을 지우고 새 커밋을 만들어도, 이전 커밋에는 그 2.3GB 가 그대로 들어 있습니다. 그 이전 커밋이 push 대상에 포함되니 계속 막힙니다.

히스토리 자체에서 파일을 빼내야 합니다.

히스토리에 남은 대용량 파일 찾기

무엇이 히스토리에 박혀 있는지 확인합니다.

git rev-list --objects --all \
  | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
  | awk '/^blob/ && $3 > 52428800 {print $3, $4}' \
  | sort -rn

50MB(52428800 바이트) 넘는 blob 을 큰 순서로 보여줍니다. 워킹 디렉토리에서 이미 지운 파일도 히스토리에 있으면 여기 나옵니다.

git-filter-repo로 히스토리에서 제거

pip install git-filter-repo

git filter-branch 라는 오래된 방법도 있지만 느리고 위험합니다. git-filter-repo 가 공식적으로 권장되는 도구입니다.

git filter-repo \
  --path AWS/s3/2023_back_log.json \
  --path AWS/s3/2024_back_log.json \
  --path some_bucket_backup.zip \
  --invert-paths \
  --force
  • --invert-paths : 지정한 경로를 제외한 나머지를 유지합니다. 즉 이 파일들만 히스토리에서 빼냅니다.
  • --force : 기존 커밋이 있는 리포에서 강제로 실행합니다.

워킹 디렉토리의 실제 파일은 그대로 두고 히스토리에서만 빠지니, 작업하던 파일이 사라질 걱정은 없습니다.

예방 — 애초에 git에 안 넣기

대용량 파일은 처음부터 git 에 안 넣는 게 맞습니다. 백업이나 데이터 덤프는 S3 같은 오브젝트 스토리지에 두고, git 에는 그 위치만 적습니다. 정말 큰 파일을 버전 관리해야 하면 Git LFS 를 씁니다.

히스토리를 다시 쓰면 커밋 해시가 전부 바뀝니다. 혼자 쓰는 리포면 상관없지만, 남과 공유하는 리포라면 다른 사람들이 다시 클론하거나 히스토리를 맞춰야 합니다. 그래서 이 작업은 “이미 사고가 난 뒤의 수습” 이고, 안 만드는 게 제일 낫습니다.

참고

  1. 불러오는 중