리포지토리 크기

  • GitLab 15.3에 도입됨, 대체 리포지토리 크기 계산을 위한 기능 플래그 gitaly_revlist_for_repo_sizegitaly_catfile_repo_size.

자체 관리 GitLab에서는 기본적으로 GitLab이 du -sk 명령을 사용하여 리포지토리의 크기를 결정합니다. GitLab은 기능 플래그 gitaly_revlist_for_repo_size로 활성화된 git-rev-list 또는 기능 플래그 gitaly_catfile_repo_size로 활성화된 git-cat-file을 대신 사용할 수 있습니다. 다양한 계산 방법 간 전환을 원할 경우 관리자가 기능 플래그를 활성화하거나 비활성화하면 됩니다.

프로젝트 개요 페이지는 리포지토리의 모든 파일 크기를 보여줍니다. 크기는 15분마다 업데이트됩니다. 파일 크기는 리포지토리 파일, 아티팩트, LFS를 포함합니다.

크기는 압축, 유지 관리 및 기타 요인으로 인해 한 인스턴스에서 다른 인스턴스로 약간 차이가 있을 수 있습니다. 관리자는 리포지토리 크기 제한을 설정할 수 있습니다.

GitLab은 GitLab.com의 크기 제한을 설정합니다. 더 많은 정보는 계정 및 제한 설정을 참조하세요.

리포지토리 크기 줄이기

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

Git 리포지토리는 시간이 지남에 따라 커집니다. 대형 파일이 Git 리포지토리에 추가되면:

  • 리포지토리를 가져오는 것이 느려집니다. 모든 사용자가 파일을 다운로드해야 하므로
  • 서버에 큰 저장 공간을 차지합니다.
  • Git 리포지토리 저장소 한도 에 도달할 수 있습니다.

리포지토리를 재작성하면 원치 않는 기록을 제거하여 리포지토리를 작게 만들 수 있습니다. 우리는 git filter-repogit filter-branchBFG보다 권장합니다.

caution
리포지토리 기록을 재작성하는 것은 파괴적인 작업입니다. 시작하기 전에 리포지토리를 백업했는지 확인하세요. 리포지토리를 백업하는 가장 좋은 방법은 프로젝트 내보내기입니다.

리포지토리 크기 계산

리포지토리의 크기는 리포지토리에 있는 모든 파일의 누적 크기를 계산하여 결정됩니다. 이는 리포지토리의 해시 저장 경로에서 du --summarize --bytes를 실행하는 것과 유사합니다.

리포지토리 기록에서 파일 제거

GitLab은 유지 관리의 일환으로 도달할 수 없는 객체를 정리합니다. GitLab에서 리포지토리의 디스크 크기를 수동으로 줄이려면 먼저 대형 파일에 대한 참조를 브랜치, 태그, GitLab에 의해 생성된 기타 내부 참조(ref)에서 제거해야 합니다. 이러한 refs에는 다음이 포함됩니다.

  • refs/merge-requests/*
  • refs/pipelines/*
  • refs/environments/*
  • refs/keep-around/*
note
각각의 참조에 대한 자세한 내용은 GitLab 특화 참조를 참조하세요.

이 refs는 자동으로 다운로드되지 않으며 숨겨진 refs는 광고되지 않지만, 프로젝트 내보내기를 사용하여 이러한 refs를 제거할 수 있습니다.

caution
이 과정은 비밀번호나 키와 같은 민감한 데이터를 리포지토리에서 제거하는 데 적합하지 않습니다. 커밋에 대한 정보, 파일 내용 포함, 데이터베이스에 캐시되며, 리포지토리에서 제거된 후에도 여전히 보입니다. 민감한 데이터를 제거하려면 블롭 제거 방법을 사용하세요.

GitLab 리포지토리에서 파일을 제거하려면:

  1. git filter-repo와 선택적으로 git-sizer를 지원 패키지 관리자를 사용하거나 소스에서 설치합니다.

  2. 프로젝트 내보내기에서 새 내보내기를 생성하고 다운로드합니다. 이 프로젝트 내보내기는 리포지토리 refs의 백업 복사본을 포함하여 파일을 제거하는 데 사용됩니다.

    전체 프로젝트 내보내기가 프로젝트 크기로 인해 신뢰성 있게 완료되지 않으면, 프로젝트 관계 내보내기 API를 사용하여 다른 내보내기 구성 요소와 독립적으로 리포지토리의 복사본을 얻을 수 있습니다.

  3. 백업을 tar로 압축 해제합니다:

    tar xzf project-backup.tar.gz
    

    여기에는 git bundle로 생성된 project.bundle 파일이 포함됩니다.

  4. --bare--mirror 옵션을 사용하여 번들에서 리포지토리의 새 복사본을 클론합니다:

    git clone --bare --mirror /path/to/project.bundle
    
  5. project.git 디렉토리로 이동합니다:

    cd project.git
    
  6. 번들 파일에서 클론하면 origin 원격이 로컬 번들 파일로 설정되므로, 리포지토리의 URL로 변경합니다:

    git remote set-url origin https://gitlab.example.com/<namespace>/<project_name>.git
    
  7. git filter-repo 또는 git-sizer를 사용하여 리포지토리를 분석하고 제거하고 싶은 항목을 결정하기 위해 결과를 검토합니다:

    # git filter-repo 사용
    git filter-repo --analyze
    head filter-repo/analysis/*-{all,deleted}-sizes.txt
    
    # git-sizer 사용
    git-sizer
    
  8. 관련 git filter-repo 옵션을 사용하여 리포지토리의 기록을 제거합니다. 두 가지 일반적인 옵션은 다음과 같습니다:

    • 특정 파일 제거를 위한 --path--invert-paths:

      git filter-repo --path path/to/file.ext --invert-paths
      
    • 예를 들어 10M보다 큰 모든 파일을 제거하기 위한 --strip-blobs-bigger-than:

      git filter-repo --strip-blobs-bigger-than 10M
      

    더 많은 예제와 전체 문서는 git filter-repo 문서를 참고하세요.

  9. 내부 refs를 제거하려고 하므로 각 실행에서 생성된 commit-map 파일이 필요하여 제거할 내부 refs를 알려줍니다. 각 git filter-repo 실행은 새로운 commit-map을 생성하며, 이전 실행의 commit-map을 덮어씁니다. 다음 명령을 사용하여 각 commit-map 파일을 백업할 수 있습니다:

    cp filter-repo/commit-map ./_filter_repo_commit_map_$(date +%s)
    

    이 단계와 이후 모든 단계(예: 리포지토리 정리 단계)를 모든 git filter-repo 명령을 실행할 때마다 반복합니다.

  10. 변경 사항을 강제로 푸시할 수 있도록 미러 플래그를 해제해야 합니다:

    git config --unset remote.origin.mirror
    
  11. 모든 브랜치를 GitLab에서 덮어쓰도록 강제 푸시합니다:

    git push origin --force 'refs/heads/*'
    

    보호된 브랜치로 인해 이 작업이 실패할 수 있습니다. 진행하려면 브랜치 보호를 제거하고 푸시한 후 보호된 브랜치를 다시 활성화해야 합니다.

  12. 태그 릴리스에서 대형 파일을 제거하려면, GitLab의 모든 태그에 강제 푸시합니다:

    git push origin --force 'refs/tags/*'
    

    보호된 태그로 인해 이 작업이 실패할 수 있습니다. 진행하려면 태그 보호를 제거하고 푸시한 후 보호된 태그를 다시 활성화해야 합니다.

  13. 더 이상 존재하지 않는 커밋에 대한 끊어진 링크를 방지하려면 git filter-repo로 생성된 refs/replace를 푸시합니다.

    git push origin --force 'refs/replace/*'
    

    이 작업이 작동하는 방법에 대한 정보는 Git replace 문서를 참조하세요.

  14. 다음 단계 시도 전에 최소 30분을 기다리세요.

  15. 리포지토리 정리를 실행하세요. 이 과정은 30분 이상 된 객체만 정리합니다. 공간이 해제되지 않음에 대한 자세한 정보는 это 번역하여 확인하세요.

리포지토리 정리

리포지토리 정리를 통해 객체의 텍스트 파일을 업로드하면 GitLab이 이 객체들에 대한 내부 Git 참조를 제거합니다.

git filter-repo를 사용하여 리포지토리 정리에 사용할 수 있는 객체 목록( commit-map 파일)을 생성할 수 있습니다.

안전하게 리포지토리를 정리하려면 작업 기간 동안 읽기 전용으로 설정해야 합니다.

이 과정은 자동으로 발생하지만, 진행 중인 쓰기가 있을 경우 정리 요청 제출이 실패하므로, 계속하기 전에 진행 중인 git push 작업이 있으면 취소하세요.

경고:
내부 Git 참조를 제거하면 관련된 병합 요청 커밋, 파이프라인, 변경 사항 세부정보가 더 이상 사용할 수 없게 됩니다.

리포지토리를 정리하려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.

  2. 설정 > 리포지토리로 이동합니다.

  3. 리포지토리 유지보수를 확장합니다.

  4. 객체 목록을 업로드합니다. 예를 들어, filter-repo 디렉토리에 위치한 git filter-repo가 생성한 commit-map 파일입니다.

    commit-map 파일이 너무 크면 백그라운드 정리 프로세스가 타임아웃되어 실패할 수 있습니다.

    이로 인해 리포지토리 크기가 예상대로 줄어들지 않을 수 있습니다. 이 문제를 해결하려면 파일을 나누어 여러 부분으로 업로드합니다.

    20000부터 시작하고 필요에 따라 줄입니다. 예를 들어:

    split -l 20000 filter-repo/commit-map filter-repo/commit-map-
    
  5. 정리 시작을 선택합니다.

이 과정은:

  • 오래된 커밋에 대한 내부 Git 참조를 제거합니다.

  • 리포지토리에 대해 git gc --prune=30.minutes.ago를 실행하여 참조되지 않은 객체를 제거합니다. 리포지토리를 재패킹하면 일시적으로 리포지토리 크기가 크게 증가하는데, 이는 이전 패키지 파일이 새로운 패키지 파일이 생성될 때까지 제거되지 않기 때문입니다.

  • 프로젝트에 연결된 사용하지 않는 LFS 객체를 링크 해제하여 저장 공간을 해제합니다.

  • 디스크에서 리포지토리의 크기를 재계산합니다.

GitLab은 정리가 완료된 후 재계산된 리포지토리 크기와 함께 이메일 알림을 보냅니다.

리포지토리 크기가 줄어들지 않는 경우, 이는 최근 30분 이내에 발생한 Git 작업에 참조된 느슨한 객체가 남아 있어서일 수 있습니다.

리포지토리가 최소 30분간 사용되지 않은 상태에서 이러한 단계를 다시 실행해 보세요.

리포지토리 정리를 사용할 때 유의사항:

  • 프로젝트 통계는 캐시됩니다. 저장소 사용량이 감소하는 것을 보려면 5-10분 기다려야 할 수 있습니다.

  • 정리는 30분 이상 된 느슨한 객체를 제거합니다. 이는 최근 30분 이내에 추가되거나 참조된 객체가 즉시 제거되지 않음을 의미합니다.

    Gitaly 서버에 접근할 수 있는 경우, 해당 지연을 생략하고 git gc --prune=now 명령을 실행하여 모든 느슨한 객체를 즉시 제거할 수 있습니다.

  • 이 과정은 GitLab 캐시 및 데이터베이스에서 일부 다시 작성된 커밋 복사본을 제거하지만, 여전히 여러 격차가 존재하며 일부 복사본은 무기한 지속될 수 있습니다.

    인스턴스 캐시 지우기는 일부를 제거하는 데 도움이 될 수 있지만, 보안 목적을 위해 의존해서는 안 됩니다!

블롭 제거

사고로 커밋된 민감한 정보나 기밀 정보를 영구적으로 삭제하여 리포지토리의 기록에서 더 이상 접근할 수 없도록 합니다.

대신 문자열을 ***REMOVED***로 바꾸려면 텍스트 수정을 참조하세요.

사전 요구사항:

  • 프로젝트에 대한 소유자 역할이 있어야 합니다.
  • 제거할 객체 ID 목록가 필요합니다.

리포지토리에서 블롭을 제거하려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.

  2. 설정 > 리포지토리를 선택합니다.

  3. 리포지토리 유지보수를 확장합니다.

  4. 블롭 제거를 선택합니다.

  5. 서랍에서 제거할 블롭 ID 목록을 입력하고, 각 ID를 별도의 줄에 입력합니다.

  6. 블롭 제거를 선택합니다.

  7. 확인 대화상자에서 프로젝트 경로를 입력합니다.

  8. 예, 블롭 제거를 선택합니다.

  9. 왼쪽 사이드바에서 설정 > 일반을 선택합니다.

  10. 고급이라는 섹션을 확장합니다.

  11. 하우스키핑 실행을 선택합니다.

객체 ID 목록 가져오기

Blob을 제거하려면 제거할 객체 목록이 필요합니다.

이 ID를 얻으려면 Git ls-tree 명령을 사용하세요.

사전 요구 사항:

  • 리포지토리가 로컬 머신에 클론되어 있어야 합니다.

예를 들어, 특정 커밋 또는 브랜치에서 크기별로 정렬된 파일 목록을 가져오려면:

  1. 터미널을 열고 리포지토리 디렉터리로 이동합니다.
  2. 다음 명령어를 실행합니다:

    git ls-tree -r -t --long --full-name <COMMIT/BRANCH> | sort -nk 4
    

    예제 출력:

    100644 blob 8150ee86f923548d376459b29afecbe8495514e9  133508 doc/howto/img/remote-development-new-workspace-button.png
    100644 blob cde4360b3d3ee4f4c04c998d43cfaaf586f09740  214231 doc/howto/img/dependency_proxy_macos_config_new.png
    100644 blob 2ad0e839a709e73a6174e78321e87021b20be445  216452 doc/howto/img/gdk-in-gitpod.jpg
    100644 blob 115dd03fc0828a9011f012abbc58746f7c587a05  242304 doc/howto/img/gitpod-button-repository.jpg
    100644 blob c41ebb321a6a99f68ee6c353dd0ed29f52c1dc80  491158 doc/howto/img/dependency_proxy_macos_config.png
    

    출력의 세 번째 열은 blob의 객체 ID입니다.

대안으로, Repositories API list repository tree 엔드포인트를 사용하여 이러한 ID를 얻을 수 있습니다.

저장소 제한

리포지토리 크기 제한:

프로젝트가 크기 제한에 도달하면 다음을 수행할 수 없습니다:

  • 프로젝트에 푸시할 수 없습니다.
  • 새 병합 요청을 생성할 수 없습니다.
  • 기존 병합 요청을 병합할 수 없습니다.
  • LFS 객체를 업로드할 수 없습니다.

여전히 다음을 수행할 수 있습니다:

  • 새 이슈 생성.
  • 프로젝트 클론.

리포지토리 크기 제한을 초과하는 경우 다음을 수행할 수 있습니다:

  1. 일부 데이터 제거.
  2. 새 커밋 만들기.
  3. 리포지토리에 푸시.

이러한 조치가 불충분한 경우 다음을 수행할 수 있습니다:

  • 일부 blob을 LFS로 이동.
  • 기록에서 오래된 종속성 업데이트 제거.

불행히도 이 워크플로우는 작동하지 않습니다. 커밋에서 파일을 삭제하는 것이 실제로 리포지토리 크기를 줄이지 않기 때문입니다. 이전 커밋과 blob은 여전히 존재합니다. 대신에, 기록을 다시 작성해야 합니다. 오픈 소스 커뮤니티에서 유지 관리되는 도구인 git filter-repo를 사용해야 합니다.

참고:
git gc가 GitLab 측에서 실행될 때까지 “제거된” 커밋과 blob은 여전히 존재합니다. 또한, 변경된 기록을 GitLab에 푸시할 수 있어야 하며, 이는 이미 최대 크기 제한을 초과한 경우 불가능할 수 있습니다.

이러한 제한을 해제하려면, 자체 관리 GitLab 인스턴스의 관리자가 초과한 특정 프로젝트의 제한을 증가시켜야 합니다. 따라서 항상 제한 이하로 유지하는 것이 좋습니다. 제한에 도달하고 임시로 증가시킬 수 없는 경우, 유일한 선택은:

  1. 로컬에서 불필요한 모든 내용을 정리합니다.
  2. GitLab에서 새 프로젝트를 만들어 대신 사용하기 시작합니다.

문제 해결

GUI에 잘못된 리포지토리 통계 표시

표시된 크기 또는 커밋 수가 내보낸 .tar.gz 또는 로컬 리포지토리와 다를 경우,
GitLab 관리자가 업데이트를 강제로 진행할 수 있도록 요청할 수 있습니다.

rails 콘솔을 사용하여:

p = Project.find_by_full_path('<namespace>/<project>')
pp p.statistics
p.statistics.refresh!
pp p.statistics
# 이전 값과 비교

# 프로젝트 통계를 지우는 대체 방법
p.repository.expire_all_method_caches
UpdateProjectStatisticsWorker.perform_async(p.id, ["commit_count","repository_size","storage_size","lfs_objects_size"])

# 총 아티팩트 스토리지 공간을 별도로 확인
builds_with_artifacts = p.builds.with_downloadable_artifacts.all

artifact_storage = 0
builds_with_artifacts.find_each do |build|
  artifact_storage += build.artifacts_size
end

puts "#{artifact_storage} bytes"

공간이 해제되지 않음

이 페이지에 정의된 프로세스는 리포지토리 내보내기의 크기를 줄일 수 있지만,
웹 UI와 터미널 모두에서 파일 시스템의 사용량은 변하지 않는 것처럼 보일 수 있습니다.

프로세스는 리포지토리에 많은 접근할 수 없는 객체들을 남깁니다.
이 객체들은 접근할 수 없기 때문에 내보내기에 포함되지 않지만 여전히 파일 시스템에 저장됩니다.
이 파일들은 두 주의 유예 기간 후에 정리됩니다. 정리는 이러한 파일들을 삭제하고
저장소 사용 통계가 정확하게 유지되도록 보장합니다.

이 프로세스를 빠르게 진행하려면
‘접근할 수 없는 객체 정리’ 유지 보수 작업을 참조하세요.

Sidekiq 프로세스가 프로젝트 내보내기에 실패함

Tier: Free, Premium, Ultimate Offering: Self-managed, GitLab Dedicated

가끔 Sidekiq 프로세스가 프로젝트를 내보내는 데 실패할 수 있으며, 이는
실행 중에 종료되는 경우와 같습니다.

GitLab.com 사용자들은 이 문제를 해결하기 위해 지원팀에 연락해야 합니다.

자체 관리 사용자들은 Rails 콘솔을 사용하여 Sidekiq 프로세스를 우회하고
수동으로 프로젝트 내보내기를 트리거할 수 있습니다:

project = Project.find(1)
current_user = User.find_by(username: 'my-user-name')
RequestStore.begin!
ActiveRecord::Base.logger = Logger.new(STDOUT)
params = {}

::Projects::ImportExport::ExportService.new(project, current_user, params).execute(nil)

이렇게 하면 UI를 통해 내보내기가 가능해지지만 사용자에게 이메일이 전송되지는 않습니다.
수동으로 프로젝트 내보내기를 트리거하고 이메일을 전송하려면:

project = Project.find(1)
current_user = User.find_by(username: 'my-user-name')
RequestStore.begin!
ActiveRecord::Base.logger = Logger.new(STDOUT)
params = {}

ProjectExportWorker.new.perform(current_user.id, project.id)