부분 복제를 사용하여 복제 크기 축소

Git 리포지터리가 커질수록 업무 처리가 번거로워질 수 있습니다. 다음과 같은 이유로 인해:

  • 다운로드해야 하는 많은 양의 히스토리
  • 필요로 하는 대용량 디스크 공간

부분 복제란 리포지터리의 완전한 복사본 없이도 Git이 작동할 수 있도록 하는 성능 최적화입니다. 이 작업의 목표는 Git이 매우 큰 리포지터리를 더 잘 처리할 수 있도록 하는 것입니다.

Git 2.22.0 이상이 필요합니다.

파일 크기 별로 필터링

Git에 대용량 이진 파일을 저장하는 것은 일반적으로 권장되지 않습니다. 왜냐하면 추가된 대용량 파일은 이후에 복제하거나 변경 사항을 가져오는 사람들에 의해 모두 다운로드되기 때문입니다. 이러한 다운로드는 느리고 문제가 있으며 특히 느린 또는 불안정한 인터넷 연결에서 작업하는 경우에는 더 그렇습니다.

파일 크기 필터와 함께 부분 복제를 사용하면 이 문제를 해결할 수 있습니다. 이를 통해 골치아픈 대용량 파일을 복제하거나 가져오지 않습니다. Git이 누락된 파일을 만나면 필요할 때 다운로드합니다.

리포지터리를 복제할 때 --filter=blob:limit=<size> 인수를 사용하세요. 예를 들어, 1MB보다 큰 파일을 제외하고 리포지터리를 복제하려면:

git clone --filter=blob:limit=1m git@gitlab.com:gitlab-com/www-gitlab-com.git

이 명령은 다음 출력을 생성할 것입니다:

'www-gitlab-com' 복제 중...
원격: 객체 열거 중: 832467, 완료됨.
원격: 객체 개수 세는 중: 100% (832467/832467), 완료됨.
원격: 객체 압축 중: 100% (207226/207226), 완료됨.
원격: 총 832467 (델타 585563), 826624 (델타 580099) 재사용, 재사용 0
개체 수신 중: 100% (832467/832467), 2.34 GiB | 5.05 MiB/s, 완료됨.
델타 해결 중: 100% (585563/585563), 완료됨.
원격: 객체 열거 중: 146, 완료됨.
원격: 객체 개수 세는 중: 100% (146/146), 완료됨.
원격: 객체 압축 중: 100% (138/138), 완료됨.
원격: 총 146 (델타 8), 144 (델타 8) 재사용, 재사용 0
개체 수신 중: 100% (146/146), 471.45 MiB | 4.60 MiB/s, 완료됨.
델타 해결 중: 100% (8/8), 완료됨.
파일 업데이트: 100% (13008/13008), 완료됨.
콘텐츠 필터링: 100% (3/3), 131.24 MiB | 4.65 MiB/s, 완료됨.

이 출력은 Git이 다음을 수행하는 것을 나타냅니다:

  1. 1MB보다 큰 파일을 제외하고 리포지터리를 복제합니다.
  2. 기본 브랜치를 확인하는 데 필요한 누락된 대용량 파일을 다운로드합니다.

브랜치를 변경할 때 Git은 더 많은 누락된 파일을 다운로드할 수 있습니다.

객체 유형별로 필터링

수백만 개의 파일과 긴 히스토리를 갖는 리포지터리의 경우, 모든 파일을 제외하고 git sparse-checkout을 사용하여 작업 복사본의 크기를 줄일 수 있습니다.

# 모든 파일을 제외하고 리포지터리 복제
$ git clone --filter=blob:none --sparse git@gitlab.com:gitlab-com/www-gitlab-com.git
'www-gitlab-com' 복제 중...
원격: 객체 열거 중: 678296, 완료됨.
원격: 객체 개수 세는 중: 100% (678296/678296), 완료됨.
원격: 객체 압축 중: 100% (165915/165915), 완료됨.
원격: 총 678296 (델타 472342), 673292 (델타 467476) 재사용, 재사용 0
개체 수신 중: 100% (678296/678296), 81.06 MiB | 5.74 MiB/s, 완료됨.
델타 해결 중: 100% (472342/472342), 완료됨.
원격: 객체 열거 중: 28, 완료됨.
원격: 객체 개수 세는 중: 100% (28/28), 완료됨.
원격: 객체 압축 중: 100% (25/25), 완료됨.
원격: 총 28 (델타 0), 12 (델타 0) 재사용, 재사용 0
개체 수신 중: 100% (28/28), 140.29 KiB | 341.00 KiB/s, 완료됨.
파일 업데이트: 100% (28/28), 완료됨.

$ cd www-gitlab-com

$ git sparse-checkout set data --cone
원격: 객체 열거 중: 301, 완료됨.
원격: 객체 개수 세는 중: 100% (301/301), 완료됨.
원격: 객체 압축 중: 100% (292/292), 완료됨.
원격: 총 301 (델타 16), 102 (델타 9) 재사용, 재사용 0
개체 수신 중: 100% (301/301), 1.15 MiB | 608.00 KiB/s, 완료됨.
델타 해결 중: 100% (16/16), 완료됨.
파일 업데이트: 100% (302/302), 완료됨.

더 많은 세부 내용은 Git 문서의 sparse-checkout을 참조하세요.

파일 경로별로 필터링

부분 복제와 희소 체크아웃 간의 더 깊은 통합은 --filter=sparse:oid=<blob-ish> 필터 스펙을 통해 가능합니다. 이 유형의 필터링은 .gitignore 파일과 유사한 형식을 사용하여 복제 및 가져오기할 때 포함할 파일을 지정합니다.

caution
sparse 필터를 사용한 부분 복제는 여전히 실험적입니다. 복제 및 가져오기 시 Gitaly 자원 사용량이 느려질 수 있으며 크게 증가할 수 있습니다. 이러한 이유로 git-sparse-checkout은 이 유형의 부분 복제 사용을 간소화하고 제한을 극복합니다.

더 많은 세부 내용은 Git 문서의 rev-list-options를 참조하세요.

  1. 필터 스펙 생성. 예를 들어 각각 다른 하위 디렉터리에 많은 애플리케이션이 있는 단일 리포지터리를 고려해 보겠습니다. shiny-app/.filterspec 파일을 생성합니다:

    # 파일은 `--filter=sparse:oid=shiny-app/.gitfilterspec`를 사용하여 부분 복제를 수행할 때 다운로드됩니다.
       
    # git config --local core.sparsecheckout true를 사용하여 드문 체크아웃을 구성하는 데 필요한 필터스펙을 명시적으로 포함
    # git show master:snazzy-app/.gitfilterspec >> .git/info/sparse-checkout
    shiny-app/.gitfilterspec
       
    # Shiny App
    shiny-app/
       
    # 의존성
    shimmery-app/
    shared-component-a/
    shared-component-b/
    
  2. 경로별로 복제 및 필터링 생성. clone 명령을 사용한 --filter=sparse:oid 지원은 희소 체크아웃과 완전히 통합되지 않았습니다.

    # 서버에 저장된 필터스펙을 사용하여 필터링된 객체 집합을 복제합니다. 경고: 이 단계는 아주 느릴 수 있습니다!
    git clone --sparse --filter=sparse:oid=master:shiny-app/.gitfilterspec <url>
       
    # 선택 사항: 아직 가져오지 않은 누락된 객체가 있는지 확인
    git rev-list --all --quiet --objects --missing=print | wc -l
    
    caution
    bash, Zsh 등과 Git 상태 정보를 자동으로 보여주는 편집기와의 Git 통합은 종종 git fetch를 실행합니다. 전체 리포지터리를 가져오므로 이러한 통합을 비활성화하거나 다시 구성해야 할 수 있습니다.

부분 클론 필터 제거

부분 클론 필터가 적용된 Git 리포지터리의 필터를 제거할 수 있습니다. 필터를 제거하려면 다음을 수행합니다:

  1. 필터로 제외된 모든 것들을 가져와서 리포지터리가 완전한지 확인합니다. git sparse-checkout을 사용했다면, 비활성화하기 위해 git sparse-checkout disable를 사용합니다. 자세한 내용은 disable 문서를 참조하세요.

    그런 다음 일반적인 fetch를 수행하여 리포지터리가 완전한지 확인합니다. 또한 git sparse-checkout을 사용하지 않을 때 빠뜨린 객체를 가져오기 위해 다음 명령어를 사용하여 가져와야 할 빠뜨린 객체가 있는지 확인하고 가져올 수 있습니다:

    # 빠뜨린 객체 표시
    git rev-list --objects --all --missing=print | grep -e '^\?'
       
    # '?' 문자가 없는 빠뜨린 객체만 표시 (GNU grep이 필요)
    git rev-list --objects --all --missing=print | grep -oP '^\?\K\w+'
       
    # 빠뜨린 객체 가져오기
    git fetch origin $(git rev-list --objects --all --missing=print | grep -oP '^\?\K\w+')
       
    # 빠뜨린 객체 수 표시
    git rev-list --objects --all --missing=print | grep -e '^\?' | wc -l
    
  2. 모든 것을 다시 패킹합니다. 예를 들어, git repack -a -d를 사용하여 이 작업을 수행할 수 있습니다. 이로써 .git/objects/pack/에는 세 개의 파일만 남아야 합니다:
    • pack-<SHA1>.pack 파일.
    • 해당하는 pack-<SHA1>.idx 파일.
    • pack-<SHA1>.promisor 파일.
  3. .promisor 파일을 삭제합니다. 위 단계를 거치면 pack-<SHA1>.promisor 파일 하나만 남아있어야 하며, 이 파일은 비어 있어야 하며 삭제해야 합니다.

  4. 부분 클론 구성을 삭제합니다. 부분 클론과 관련된 구성 변수는 Git 구성 파일에서 제거되어야 합니다. 일반적으로 다음 구성만 제거하면 됩니다:
    • remote.origin.promisor.
    • remote.origin.partialclonefilter.