부분 복제

Git 리포지터리가 커지면 다음과 같은 이유로 작업이 불편해질 수 있습니다.

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

부분 복제 은 “리포지터리의 완전한 복사본 없이도 Git이 작동할 수 있게 하는 성능 최적화”입니다. 이 작업의 목표는 Git이 극도로 큰 리포지터리를 더 잘 다룰 수 있도록 하는 것입니다.

Git 2.22.0 이상이 필요합니다.

파일 크기별로 필터링

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

부분 복제를 사용하여 파일 크기 필터와 함께 사용하면 이 문제를 해결할 수 있습니다. 이는 골치아픈 큰 파일들을 복제 및 가져오기에서 제외시킴으로써 이루어집니다. Git이 누락된 파일을 만나면 필요할 때 다운로드됩니다.

리포지터리를 복제할 때 --filter=blob:limit=<size> 인수를 사용합니다. 예를 들어 파일 크기가 1메가바이트보다 큰 파일을 제외하고 리포지터리를 복제하려면 다음과 같이 합니다.

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

이렇게 하면 다음 출력이 생성됩니다.

'www-gitlab-com'으로 복제하는 중...
remote: 객체 나열중: 832467, 완료.
remote: 객체 개수 세는중: 100% (832467/832467), 완료.
remote: 객체 압축중: 100% (207226/207226), 완료.
remote: 총 832467 (델타 585563), 재사용 826624 (델타 580099), 0팩
객체 받는중: 100% (832467/832467), 2.34 GiB | 5.05 MiB/s, 완료.
델타 알아내는중: 100% (585563/585563), 완료.
remote: 객체 나열중: 146, 완료.
remote: 객체 개수 세는중: 100% (146/146), 완료.
remote: 객체 압축중: 100% (138/138), 완료.
remote: 총 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. 1메가바이트보다 큰 파일을 제외하고 리포지터리를 복제합니다.
  2. 기본 브랜치를 확인하기 위해 필요한 누락된 큰 파일을 다운로드합니다.

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

객체 유형별로 필터링

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

# 모든 파일을 제외하고 리포지터리를 복제
$ git clone --filter=blob:none --sparse git@gitlab.com:gitlab-com/www-gitlab-com.git
'www-gitlab-com'으로 복제하는 중...
remote: 객체 나열중: 678296, 완료.
remote: 객체 개수 세는중: 100% (678296/678296), 완료.
remote: 객체 압축중: 100% (165915/165915), 완료.
remote: 총 678296 (델타 472342), 재사용 673292 (델타 467476), 0팩
객체 받는중: 100% (678296/678296), 81.06 MiB | 5.74 MiB/s, 완료.
델타 알아내는중: 100% (472342/472342), 완료.
remote: 객체 나열중: 28, 완료.
remote: 객체 개수 세는중: 100% (28/28), 완료.
remote: 객체 압축중: 100% (25/25), 완료.
remote: 총 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
remote: 객체 나열중: 301, 완료.
remote: 객체 개수 세는중: 100% (301/301), 완료.
remote: 객체 압축중: 100% (292/292), 완료.
remote: 총 301 (델타 16), 재사용 102 (델타 9), 0팩
객체 받는중: 100% (301/301), 1.15 MiB | 608.00 KiB/s, 완료.
델타 알아내는중: 100% (16/16), 완료.
파일 업데이트: 100% (302/302), 완료.

자세한 내용은 sparse-checkout에 대한 Git 설명서를 참조하십시오.

파일 경로별로 필터링

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

caution
sparse 필터를 사용한 부분 복제는 여전히 실험적입니다. 복제 및 가져오기 시 Gitaly 자원 활용도를 느리게 할 수 있으며 중요하게 증가시킬 수 있습니다. 대신에 모든 블롭을 필터링하고 sparse-checkout을 사용하여 이러한 부분 복제 사용에 대한 제한을 극복하는 것이 좋습니다. 왜냐하면 git-sparse-checkout이 이러한 유형의 부분 복제를 간소화하고 그 제한을 극복하기 때문입니다.

자세한 내용은 rev-list-options에 대한 Git 설명서를 참조하십시오.

  1. 필터 사양 생성하기. 예를 들어, 루트 디렉터리의 서로 다른 하위 디렉터리에 많은 응용프로그램이 있는 단일 리포지터리를 고려해 보십시오. shiny-app/.filterspec 파일을 생성합니다.

    # 이 파일에 나열된 경로만을 사용하여 부분 복제 시 다운로드됩니다
    # `git config --local core.sparsecheckout true`를 사용하여 희소 체크아웃을 구성하는 데 필요한 필터 사양을 명시적으로 포함
    # git show master:snazzy-app/.gitfilterspec >> .git/info/sparse-checkout
    shiny-app/.gitfilterspec
       
    # Shiny App
    shiny-app/
       
    # Dependencies
    shimmery-app/
    shared-component-a/
    shared-component-b/
    
  2. 경로별로 복제 및 필터링. --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.