클라우드 Mac 한 대가 몇 주 동안 연속으로 빌드를 수행하고 나면 git fetch는 여전히 빠르더라도 브랜치 전환, 병합 기준점 계산, 객체 순회는 점차 느려질 수 있습니다. 흔한 원인은 네트워크가 아니라 장기간 유지된 저장소에 누적된 수많은 느슨한 객체, 파편화된 pack 파일, 더 이상 유효하지 않은 원격 참조, 그리고 여러 차례 중단된 작업이 남긴 유지 관리 잠금입니다. .git을 삭제하고 다시 클론하는 방법은 간단하지만, 기존 객체 캐시를 잃게 되고 문제 발생 시점만 다음 주기로 미룰 뿐입니다.
더 안정적인 방법은 저장소 유지 관리를 독립된 작업으로 운영하는 것입니다. 먼저 상태를 수치화하고, 상호 배제된 상태에서 증분 작업을 실행한 다음, 마지막으로 객체 연결성을 검증합니다. 아래 절차는 고정 작업 공간뿐 아니라 여러 worktree를 사용하는 빌드 노드에도 적합합니다.
비교 가능한 저장소 기준선 만들기
처음부터 디렉터리 전체 크기만 확인해서는 안 됩니다. Git 객체의 수, 구성 방식, 도달 가능성이 문제를 더 정확히 보여 줍니다. 저장소로 이동한 뒤 다음 결과를 기록합니다.
git count-objects -vH
git rev-parse --git-dir
git rev-parse --git-common-dir
git for-each-ref --format='%(refname)' refs/remotes | wc -l
find "$(git rev-parse --git-common-dir)/objects/pack" -name '*.pack' | wc -l
count가 높으면 느슨한 객체가 많다는 뜻이며, packs가 계속 증가한다면 이전 작업들이 작은 pack을 반복해서 생성하고 있다는 의미입니다. worktree를 사용할 때는 git rev-parse --git-common-dir이 반환하는 공용 디렉터리를 유지 관리 대상으로 삼아야 합니다. 현재 worktree의 .git 포인터 파일만 확인해서는 안 됩니다.
각 유지 관리 전후의 count, in-pack, packs, size-pack 값을 일반 텍스트 로그에 기록하는 것이 좋습니다. 디스크 사용량 감소만으로 성공 여부를 판단하지 마십시오. 커밋 그래프를 갱신해도 공간은 거의 줄지 않을 수 있지만, 이력 순회와 병합 기준점 조회 성능은 개선될 수 있습니다.
과도한 정리 대신 증분 작업 선택하기
Git 유지 관리 작업은 개별적으로 실행할 수 있습니다. 상시 운영되는 빌드 노드에서는 일반적으로 커밋 그래프, 느슨한 객체 정리, 증분 재패킹을 먼저 활성화합니다.
git config maintenance.strategy incremental
git maintenance run \
--task=commit-graph \
--task=loose-objects \
--task=incremental-repack
커밋 그래프는 이력 도달 가능성 조회를 가속합니다. 멀티팩 인덱스를 사용하면 Git이 모든 pack을 하나씩 스캔할 필요가 없습니다. 증분 재패킹은 객체를 단계적으로 통합하므로 한 번의 전체 정리 작업이 지나치게 많은 시간과 임시 공간을 차지하는 일을 방지합니다.
git gc --prune=now를 일상적인 예약 작업으로 사용하지 마십시오. 즉시 제거하면 복구를 위한 유예 기간이 사라지며, 이전 객체 참조를 아직 보유한 동시 실행 프로세스와 충돌할 수도 있습니다.
저장소에서 대규모 브랜치 삭제가 막 이루어진 경우에도 기본 유예 기간을 먼저 유지해야 합니다. 빌드, 체크아웃, 리베이스, 서브모듈 업데이트, 아카이브 작업이 실행 중이지 않음을 확인한 뒤에만 더 심층적인 정리를 고려하십시오.
원격 참조는 별도로 관리하기
오랫동안 정리하지 않은 원격 추적 브랜치는 순회 범위를 넓힙니다. 먼저 결과를 미리 확인한 다음 정리를 실행합니다.
git remote prune origin --dry-run
git remote prune origin
이 명령은 원격 추적 참조만 처리합니다. 객체 정리를 대신하지 않으며 로컬 개발 브랜치도 삭제하지 않습니다. 빌드 스크립트가 원격에서 이미 삭제된 참조에 의존한다면, 유효하지 않은 참조를 영구 보존하는 대신 스크립트를 먼저 수정해야 합니다.
원자적 잠금으로 빌드와 유지 관리 격리하기
유지 관리 작업과 빌드 작업은 동일한 저장소 수준 잠금을 공유해야 합니다. mkdir는 같은 파일 시스템 안에서 원자적으로 동작하므로 간단한 잠금 수단으로 적합합니다.
common_dir="$(git rev-parse --git-common-dir)"
lock_dir="$common_dir/maintenance.lock"
if ! mkdir "$lock_dir" 2>/dev/null; then
printf '%s\n' "maintenance skipped: repository is busy"
exit 0
fi
trap 'rmdir "$lock_dir"' EXIT INT TERM
git maintenance run \
--task=commit-graph \
--task=loose-objects \
--task=incremental-repack
빌드 진입점에서도 같은 잠금을 확인하거나 직접 획득해야 합니다. 유지 관리 스크립트만 일방적으로 잠그는 것은 의미가 없습니다. 여러 worktree는 객체 저장소를 공유하므로 각 작업 디렉터리에 별도의 잠금을 만들면 안 됩니다.
수동 조사에 활용할 수 있도록 잠금 디렉터리에 프로세스 ID와 시작 시간을 기록할 수 있습니다. 다만 시간이 오래되었다는 이유만으로 잠금을 바로 삭제해서는 안 됩니다. 먼저 ps로 해당 프로세스가 존재하는지 확인한 뒤 git pack-objects, git index-pack, git maintenance가 실행 중인지 점검하십시오.
인덱스와 객체 연결성 검증하기
유지 관리 명령이 종료 코드 0으로 끝났다는 것은 명령이 완료되었다는 뜻일 뿐, 저장소를 빌드에 계속 사용해도 안전하다는 보장은 아닙니다. 최소한 다음 세 가지 검증을 실행해야 합니다.
git commit-graph verify
git multi-pack-index verify
git fsck --connectivity-only
검사 항목은 다음 표와 같이 파이프라인에 반영할 수 있습니다.
검증에 실패하더라도 더 과도한 정리부터 실행하지 마십시오. 명령 출력, Git 버전, 공용 객체 디렉터리 경로, 마지막으로 성공한 빌드의 커밋 번호를 포함해 현장 정보를 보존해야 합니다. 객체가 누락되었다면 신뢰할 수 있는 원격에서 다시 가져올 수 있습니다. 그래도 복구되지 않으면 기존 디렉터리에서 삭제를 반복적으로 시도하지 말고, 해당 디렉터리를 격리한 뒤 새로 클론하십시오.
노드 수명 주기에 유지 관리 통합하기
유지 관리 주기는 모든 프로젝트에 동일한 분 단위 간격을 적용하는 대신 저장소의 변경량에 따라 결정해야 합니다. 커밋 빈도가 높은 모노레포는 매일 마지막 작업이 끝난 뒤 증분 유지 관리를 실행할 수 있습니다. 변경이 드문 프로젝트는 느슨한 객체와 pack 수의 추세를 기준으로 실행 시점을 정할 수 있습니다. 재패킹 중에는 기존 pack과 새 pack이 일시적으로 함께 존재하므로 실행 전에 사용 가능한 디스크 공간도 확인해야 합니다.
VMOak의 클라우드 Mac에서는 유지 관리 스크립트를 저장소 외부의 읽기 전용 운영 디렉터리에 두고, 스케줄러가 대상 경로를 전달하도록 구성하는 것이 좋습니다. 일반 코드 변경이 유지 관리 로직을 덮어쓰지 못하도록 스크립트는 프로젝트 브랜치에 있는 같은 이름의 파일을 읽지 않아야 합니다. 노드에서 여러 저장소를 운영한다면 저장소별로 잠그고 검증해야 하며, 한 저장소의 실패가 다른 저장소의 정리 작업을 유발해서는 안 됩니다.
최종 검수에서는 단순히 “공간이 줄었는지”만 확인해서는 안 됩니다. 원격 업데이트, 대상 커밋 체크아웃, 병합 기준점 조회, 읽기 전용 빌드 준비를 각각 한 번씩 실행한 뒤 유지 관리 전후의 로그를 비교하여 일상 작업의 성능이 저하되지 않았는지 확인해야 합니다. 그래야 Git 유지 관리가 디스크 공간이 부족할 때 임시로 실행하는 삭제 명령이 아니라 감사 가능한 노드 운영 작업이 됩니다.
자주 묻는 질문
빌드가 실행 중일 때 Git 유지 관리를 해도 되나요?
체크아웃, 리베이스, 패키징 작업과 동시에 실행하지 않는 편이 안전합니다. 저장소 단위 원자적 잠금을 사용하고 유휴 시간에 실행해야 합니다.
왜 git gc --prune=now를 정기 실행하지 않나요?
즉시 삭제는 복구 유예 시간을 없애고 다른 프로세스가 참조하는 객체를 제거할 위험을 키웁니다. 장기 노드에는 증분 재패킹이 더 적합합니다.
유지 관리 후 무엇을 검사해야 하나요?
commit-graph, multi-pack-index와 객체 연결성을 검증하고 팩 수, 느슨한 객체 수, 디스크 사용량을 함께 기록해야 합니다.
빌드, 자동화 또는 원격 작업을 위한 클라우드 Mac 선택
M4 16GB와 M4 Pro 64GB 두 가지 구성을 비교하고, 대여 기간과 이용 가능한 노드를 확인한 후 주문을 제출하세요.