git gc --aggressive vs git repack


90

git저장소 크기를 줄이는 방법을 찾고 있습니다. 검색은 나를 git gc --aggressive대부분의 시간으로 인도합니다 . 나는 또한 이것이 선호되는 접근 방식이 아니라는 것을 읽었습니다.

왜? 내가 달리고 있다면 무엇을 알아야 gc --aggressive합니까?

git repack -a -d --depth=250 --window=250이상 권장됩니다 gc --aggressive. 왜? repack저장소의 크기를 줄이는 방법은 무엇입니까? 또한 플래그 --depth--window.

gc과 중에서 무엇을 선택해야 repack합니까? 언제 사용해야 gc하고 repack?

답변:


77

오늘날에는 차이가 없습니다. git gc --aggressiveLinus가 2007 년에 제안한 제안에 따라 작동합니다. 아래를 참조하십시오. 버전 2.11 (2016 년 4 분기)부터 git은 기본적으로 깊이가 50입니다. 크기가 250 인 창은 각 객체의 더 큰 섹션을 스캔하기 때문에 좋지만 250의 깊이는 모든 체인이 매우 오래된 것을 참조하기 때문에 좋지 않습니다. 이는 디스크 사용량을 약간 낮추기 위해 향후 모든 git 작업을 느리게 만듭니다 .


역사적 배경

Linus는 git gc --aggressive" 정말 나쁜 팩"또는 "정말 끔찍한 델타" 가있을 때만 사용하도록 제안했습니다 (전체 메일 링리스트 게시물은 아래 참조). 그러나 "거의 항상, 다른 경우에는 실제로는 정말 나쁜 것입니다. 해야 할 일." 결과는 시작했을 때보 다 더 나쁜 상태로 저장소를 남길 수도 있습니다!

그가 "길고 복잡한 역사"를 가져온 후이를 제대로 수행하기 위해 제안한 명령은 다음과 같습니다.

git repack -a -d -f --depth=250 --window=250

그러나 이것은 당신이 이미 당신의 저장소 히스토리에서 원치 않는 건크제거 했고 당신이 git filter-branch문서 에있는 저장소 축소 체크리스트를 따랐다 고 가정합니다 .

git-filter-branch를 사용하여 파일 하위 집합을 제거 할 수 있으며 일반적으로 --index-filter--subdirectory-filter. 사람들은 결과 리포지토리가 원본보다 작을 것으로 기대하지만 실제로 작게 만들려면 몇 가지 단계가 더 필요합니다. 먼저 다음 사항을 확인하십시오.

  • Blob이 수명 동안 이동 된 경우 파일 이름의 모든 변형을 제거했습니다. git log --name-only --follow --all -- filename이름을 바꾸는 데 도움이 될 수 있습니다.

  • 정말 모든 참조를 필터링했습니다 .을 --tag-name-filter cat -- --all호출 할 때 사용 git filter-branch합니다.

그런 다음 더 작은 저장소를 얻는 두 가지 방법이 있습니다. 더 안전한 방법은 원본을 그대로 유지하는 복제하는 것입니다.

  • 그것을 복제 git clone file:///path/to/repo. 복제본에는 제거 된 개체가 없습니다. git-clone을 참조하십시오. (일반 경로로 복제하면 모든 것이 하드 링크됩니다!)

어떤 이유로 든 복제하고 싶지 않다면 대신 다음 사항을 확인하십시오 (이 순서대로). 이것은 매우 파괴적인 접근 방식이므로 백업을 만들거나 복제로 돌아가십시오. 경고를 받았습니다.

  • git-filter-branch에 의해 백업 된 원본 참조를 제거합니다.

    git for-each-ref --format="%(refname)" refs/original/ |
      xargs -n 1 git update-ref -d
    
  • 를 사용하여 모든 리플 로그를 만료합니다 git reflog expire --expire=now --all.

  • 가비지는 참조되지 않은 모든 객체를 수집합니다 git gc --prune=now(또는 git gc에 대한 인수를 지원할만큼 새롭지 않은 --prune경우 git repack -ad; git prune대신 사용).


Date: Wed, 5 Dec 2007 22:09:12 -0800 (PST)
From: Linus Torvalds <torvalds at linux-foundation dot org>
To: Daniel Berlin <dberlin at dberlin dot org>
cc: David Miller <davem at davemloft dot net>,
    ismail at pardus dot org dot tr,
    gcc at gcc dot gnu dot org,
    git at vger dot kernel dot org
Subject: Re: Git and GCC
In-Reply-To: <4aca3dc20712052111o730f6fb6h7a329ee811a70f28@mail.gmail.com>
Message-ID: <alpine.LFD.0.9999.0712052132450.13796@woody.linux-foundation.org>
References: <4aca3dc20712051947t5fbbb383ua1727c652eb25d7e@mail.gmail.com>
            <20071205.202047.58135920.davem@davemloft.net>
            <4aca3dc20712052032n521c344cla07a5df1f2c26cb8@mail.gmail.com>
            <20071205.204848.227521641.davem@davemloft.net>
            <4aca3dc20712052111o730f6fb6h7a329ee811a70f28@mail.gmail.com>

2007 년 12 월 6 일 목요일에 Daniel Berlin은 다음과 같이 썼습니다.

실제로 git-gc --aggressiveSVN 리포지토리에서 변환했는지 여부에 관계없이 때때로 파일을 압축하는 것은 바보 같은 일을합니다.

물론. git --aggressive대부분 바보입니다. 이것은 " 정말 나쁜 팩 이 있다는 것을 알고 있으며, 제가 한 모든 나쁜 포장 결정을 버리고 싶습니다. "의 경우에만 유용 합니다.

이를 설명하기 위해 git delta-chain이 어떻게 작동하는지, 그리고 대부분의 다른 시스템과 어떻게 다른지 설명 할 가치가 있습니다 (아마도 알고 있겠지만 기본 사항을 살펴 보겠습니다).

다른 SCM에서는 일반적으로 델타 체인이 고정되어 있습니다. "앞으로"또는 "뒤로"가 될 수 있으며 리포지토리 작업에 따라 약간 씩 발전 할 수 있지만 일반적으로 단일 SCM 엔터티로 표현되는 단일 파일에 대한 일련의 변경 사항입니다. CVS에서는 분명히 *,v파일이고 다른 많은 시스템이 비슷한 일을합니다.

Git은 또한 델타 체인을 수행하지만 훨씬 더 "느슨하게"수행합니다. 고정 된 개체가 없습니다. 델타는 git이 좋은 델타 후보로 간주하는 임의의 다른 버전에 대해 생성되며 (다양한 상당히 성공적인 휴리스틱으로) 절대적으로 엄격한 그룹화 규칙이 없습니다.

이것은 일반적으로 매우 좋은 것입니다. 다양한 개념적 이유 ( , git 내부적으로는 전체 개정 체인에 대해 전혀 신경을 쓸 필요조차 없습니다. 델타 측면에서 전혀 생각하지 않습니다).하지만 융통성없는 델타 규칙을 제거하는 것은 의미가 있기 때문에 좋습니다. 예를 들어 git은 두 파일을 병합하는 데 전혀 문제가 없습니다 *,v. 숨겨진 의미가있는 임의의 "개정 파일" 이 없습니다 .

또한 델타의 선택이 훨씬 더 개방적인 질문임을 의미합니다. 델타 체인을 하나의 파일로 제한하면 델타에 대해 할 일에 대한 선택권이 많지 않지만 git에서는 완전히 다른 문제가 될 수 있습니다.

그리고 이것은 정말로 나쁜 이름 --aggressive이 들어오는 곳입니다. git은 일반적으로 델타 정보를 재사용하려고 시도하지만 (좋은 생각이고 이전에 찾은 모든 좋은 델타를 다시 찾는 CPU 시간을 낭비하지 않기 때문에) 때때로 당신은 "빈 슬레이트로 다시 시작하고 이전의 모든 델타 정보를 무시하고 새로운 델타 세트를 생성 해 보겠습니다."라고 말하고 싶습니다.

따라서 --aggressive공격적인 것이 아니라 이전에 이미 결정한 결정을 다시 수행하는 데 CPU 시간을 낭비하는 것입니다!

때때로 그것은 좋은 일입니다. 특히 일부 가져 오기 도구는 정말 끔찍하게 나쁜 델타를 생성 할 수 있습니다. git fast-import예를 들어 를 사용하는 모든 항목 에는 델타 레이아웃이 많지 않을 수 있으므로 "깨끗한 상태에서 시작하고 싶습니다."라고 말할 가치가있을 수 있습니다.

그러나 거의 항상, 다른 경우에는 실제로는 정말 나쁜 일입니다. CPU 시간을 낭비하게 될 것입니다. 특히 이전에 델타를 잘 수행했다면 최종 결과는 이미 찾은 모든 좋은 델타 를 재사용하지 않을 것입니다 . 따라서 실제로 많은 데이터를 얻게 될 것입니다. 더 나쁜 결과도!

git gc --aggressive 문서를 제거하기 위해 Junio에 패치를 보내겠습니다 . 유용 할 수 있지만 일반적으로 그것이하는 일을 매우 심층적으로 이해하고 그 문서가 그렇게하는 데 도움이되지 않는 경우에만 유용합니다.

일반적으로 증분을 수행하는 git gc것이 올바른 접근 방식이며 git gc --aggressive. 이전 델타를 재사용 할 것이고, 이전 델타를 찾을 수 없을 때 (처음에 증분 GC를 수행하는 이유!) 새로운 델타를 생성 할 것입니다.

다른 한편으로,“길고 관련된 역사의 초기 수입”은 정말 좋은 델타를 찾는 데 많은 시간을 할애 할 가치가있는 지점이라는 것은 확실히 사실입니다 . 그러면 이후 모든 사용자 ( git gc --aggressive실행 취소에 사용하지 않는 한 )는 해당 일회성 이벤트의 이점을 얻게됩니다. 따라서 특히 오랜 역사를 가진 대규모 프로젝트의 경우에는 추가 작업을 수행하여 델타 검색 코드를 야생으로 전환하는 것이 좋습니다.

따라서 git gc --aggressive-그러나 올바르게 수행됨 -에 해당하는 것은 다음과 같이 (하룻밤)하는 것입니다.

git repack -a -d --depth=250 --window=250

그 깊이는 델타 체인이 얼마나 깊을 수 있는지에 관한 것이고 (오래된 기록을 위해 더 길게 만드십시오-공간 오버 헤드의 가치가 있습니다) 윈도우는 각 델타 후보가 스캔하기를 원하는 객체 윈도우의 크기에 관한 것입니다.

그리고 여기에 -f플래그 를 추가하는 것이 좋습니다 ( "모든 오래된 델타 삭제"). 이제 실제로 이것이 좋은 후보를 실제로 찾는 지 확인하려고하기 때문입니다.

그리고 그것은 영원히 그리고 하루가 걸릴 것입니다 ( , "하룻밤"일). 그러나 최종 결과는 해당 저장소의 모든 다운 스트림이 직접 노력할 필요없이 훨씬 더 나은 팩을 얻을 수 있다는 것입니다.

          Linus

2
깊이에 대한 귀하의 의견은 약간 혼란 스럽습니다. 처음에 나는 당신이 틀렸다고 불평하려고했지만 공격적으로 git 저장소 속도를 크게 높일 수 있습니다. 공격적인 가비지 수집을 수행 한 후 git 상태를 수행하는 데 5 분이 걸린 거대한 저장소가 초로 줄었습니다. 하지만 공격적인 gc가 repo 속도를 늦추는 것이 아니라 매우 큰 깊이 크기를 의미한다는 것을 깨달았습니다.
user6856

58

언제 gc 및 repack을 사용해야합니까?

" Git Garbage collection이 완전히 작동하지 않는 것 같습니다 "에서 언급했듯이 , a git gc --aggressive만으로는 충분하지 않거나 심지어 충분하지 않습니다.
그리고 아래 에서 설명했듯이 종종 필요하지 않습니다.

가장 효과적인 조합이 추가 될 수 git repack도 있지만 git prune:

git gc
git repack -Ad      # kills in-pack garbage
git prune           # kills loose garbage

참고 : Git 2.11 (2016 년 4 분기)은 기본 gc aggressive깊이를 50 으로 설정합니다.

Jeff King ( )의 commit 07e7dbf (2016 년 8 월 11 일)를 참조하십시오 . (의해 병합 - Junio C 하마노 -0952ca8 커밋 2,016 21 구월)peff
gitster

gc: 기본 공격 깊이는 50입니다.

" git gc --aggressive"는 델타 체인 길이를 250으로 제한하는 데 사용되었습니다. 이는 추가 공간을 절약하기에는 너무 깊고 런타임 성능에 해를 끼칩니다.
한도가 50으로 줄었습니다.

요약은 다음과 같습니다. 현재 기본값 인 250은 많은 공간을 절약하지 않으며 CPU 비용이 듭니다. 좋은 절충안이 아닙니다.

" --aggressive"플래그 git-gc는 다음 세 가지 작업을 수행합니다.

  1. " -f"을 사용 하여 기존 델타를 버리고 처음부터 다시 계산합니다.
  2. 델타를 더 자세히 보려면 ​​"--window = 250"을 사용하십시오.
  3. 더 긴 델타 체인을 만들려면 "--depth = 250"을 사용하십시오.

항목 (1) 및 (2)는 "공격적인"재 포장에 적합합니다.
그들은 더 나은 팩을 얻기 위해 더 많은 계산 작업을 수행하도록 리팩에 요청합니다. 재 포장하는 동안 비용을 지불하고 다른 작업에는 혜택 만 표시됩니다.

항목 (3)은 그렇게 명확하지 않습니다.
더 긴 체인을 허용하면 델타에 대한 제한이 줄어들어 잠재적으로 더 나은 체인을 찾고 공간을 절약 할 수 있습니다.
그러나 이는 또한 델타에 액세스하는 작업이 더 긴 체인을 따라야하므로 성능에 영향을 미칩니다.
따라서 이것은 트레이드 오프이고 트레이드 오프가 좋은 것인지도 확실하지 않습니다.

( 연구 커밋 참조 )

깊이를 줄이면 일반 작업에 대한 CPU 절약이 향상된다는 것을 알 수 있습니다.
그러나 깊이가 높아질수록 공간 절약이 그다지 크지 않음을 알 수 있습니다. 10에서 50 사이에서 5-10 %를 절약하는 것은 아마도 CPU 절충의 가치가 있습니다. 50에서 100으로 가기 위해 1 %를 절약하거나 100에서 250으로 가기 위해 다른 0.5 %를 절약하는 것은 아마도 그렇지 않을 것입니다.


CPU 절약에 대해 " git repack"는 --threads=<n>옵션 을 받아들이고 팩 개체에 전달하는 방법을 배웠습니다 .

참조 40bcf31 커밋 에 의해 (2017년 4월 26일)를 Junio C 하마노 ( gitster) .
(Merged by Junio ​​C gitsterHamano -- in commit 31fb6f4 , 29 May 2017)

재 포장 : 수락 --threads=<n>및 전달pack-objects

우리는 이미 --window=<n>그리고 --depth=<n>; 이것은 사용자가 --threads=1다중 스레드 경주에 영향을받지 않고 재현 가능한 테스트 를 강제하려는 경우에 도움이됩니다 .


3
내가 링크 "완벽하게 작동하지 않는 것 망할 놈의 쓰레기 수집"는의 리누스 스레드를 언급
VonC

1
이 현대적인 업데이트에 감사드립니다 ! 여기에있는 다른 모든 대답은 오래되었습니다. 이제 git gc --aggressive두 번 수정되었음을 알 수 있습니다 . 첫째, Linus가 2007 년에 "더 나은 포장 방법"으로 제안한 것을 수행합니다. 그런 다음 Git 2.11에서는 Linus가 제안했지만 유해한 것으로 판명 된 과도한 객체 깊이를 피하기 위해 (향후 모든 Git 작업을 느리게하고 말할 가치가있는 공간을 절약하지 못함).
gw0

git gc, git repack -Ad 및 git prune이 내 저장소의 크기를 증가시킵니다 ... 왜?
개발 운영

@devops 확실하지 않음 : 어떤 버전의 Git을 사용하고 있습니까? 이에 대한 새로운 질문을 할 수 있습니다 (OS,
리포지토리

man git-repack에 대해 말한다 -d'또한 실행 자식 중복 느슨한 객체 files.`을 제거하기 위해 자두 포장 또는 않습니다 git prune또한합니까? man git-prune라고 In most cases, users should run git gc, which calls git prune.그래서 사용 후 무엇을, git gc? 단지 사용하는 것이 더 낫거나 충분하지 git repack -Ad && git gc않습니까?
Jakob

14

문제 git gc --aggressive는 옵션 이름과 문서가 오해의 소지가 있다는 것입니다.

으로 리누스 자신이이 메일에서 설명하고 , 무엇을 git gc --aggressivebasicly 일은 이것이다 :

git은 일반적으로 델타 정보를 재사용하려고 시도하지만 (좋은 생각이고 이전에 찾은 모든 좋은 델타를 다시 찾는 데 CPU 시간을 낭비하지 않기 때문입니다) 가끔은 "다시 시작합시다. 빈 슬레이트를 사용하고 이전의 모든 델타 정보를 무시하고 새로운 델타 세트를 생성 해보십시오. "

일반적으로 git은 이러한 델타를 매우 유연하게 결정하므로 git에서 델타를 다시 계산할 필요가 없습니다. 당신이 정말로 정말로 나쁜 델타를 가지고 있다는 것을 아는 경우에만 의미가 있습니다. Linus가 설명했듯이 주로 사용하는 도구 git fast-import가이 범주에 속합니다.

대부분의 경우 git은 유용한 델타를 결정하는 데 꽤 좋은 일을하며 사용 git gc --aggressive하면 많은 CPU 시간을 낭비하면서 잠재적으로 더 나쁜 델타가 남게됩니다.


리누스는 결론이 그의 메일을 종료 git repack대형으로 --depth하고 --window대부분의 시간에 더 나은 선택이다; 특히 큰 프로젝트를 가져온 후 git이 좋은 델타를 찾는 지 확인하고 싶습니다.

따라서 git gc --aggressive-그러나 올바르게 수행됨 -에 해당하는 것은 (하룻밤) 다음과 같은 일을하는 것입니다.

git repack -a -d --depth=250 --window=250

그 깊이는 델타 체인이 얼마나 깊을 수 있는지에 관한 것이고 (오래된 기록을 위해 더 길게 만드십시오-공간 오버 헤드의 가치가 있습니다), 윈도우는 각 델타 후보가 스캔하기를 원하는 객체 윈도우의 크기에 관한 것입니다.

그리고 여기에서 -f플래그 를 추가 할 수 있습니다 ( "모든 오래된 델타 삭제"). 이제 실제로 이것이 좋은 후보를 실제로 찾는 지 확인하려고하기 때문입니다.


8

주의. git gc --agressive백업이없는 경우 원격지와 동기화되지 않은 저장소로 실행하지 마십시오 .

이 작업은 처음부터 델타를 다시 생성하며 정상적으로 중단 될 경우 데이터가 손실 될 수 있습니다.

내 8GB 컴퓨터의 경우 공격적인 gc는 10k 작은 커밋으로 1Gb 저장소의 메모리가 부족합니다. OOM killer가 git 프로세스를 종료했을 때 거의 빈 저장소가 남았고 작동하는 트리와 델타가 거의 남아 있지 않았습니다.

물론 리포지토리의 유일한 사본이 아니었기 때문에 리포지토리를 다시 생성하고 원격에서 가져 왔습니다 (패치가 손상된 리포지토리에서 작동하지 않고 '델타 해결'단계에서 교착 상태에 빠졌습니다).하지만 리포지토리가 리모트가 전혀없는 단일 개발자 로컬 저장소-먼저 백업하십시오.


5

참고 : git gc --aggressiveGit 2.22 (2019 년 2 분기)에 설명 된대로.

참조 0044f77 커밋 , daecbf2 커밋 , 7,384,504 커밋 , 22d4e3b 커밋 , 080a448 커밋 , 54d56f5 커밋 , d257e0f 커밋 , b6a8d09 커밋 (2019 4월 7일), 및 fc559fb 커밋 , cf9cd77 커밋 , b11e856 커밋 에 의해 (2019년 3월 22일)을 (라고 Ævar Arnfjörð Bjarmason avar) .
(의해 병합 - Junio C 하마노 gitster-ac70c53 커밋 2,019 25 아웃 날짜)

gc 문서 : 유용성 경시 --aggressive

기존 " gc --aggressive"문서는 사용자에게 정기적으로 실행하도록 권장하지 않습니다.
저는 개인적으로이 문서를이 옵션을 사용하기위한 조언으로 받아 들인 많은 사용자들과 이야기를 나눴으며, 보통 (대부분) 시간 낭비입니다 .

따라서 이것이 실제로 무엇을하는지 명확히하고 사용자가 스스로 결론을 내 리도록합시다.

Jeff King의 설명을 간략하게 설명 하기 위해 "효과 [...]는 지속적입니다"를 명확히하겠습니다 .

즉, git-gc 문서에 다음이 포함됩니다 .

적극적인

--aggressive옵션이 제공되어, git-repack로 호출됩니다 -f차례로 전달합니다 플래그 --no-reuse-delta자식 팩 - 객체 .
이것은 재 포장에 훨씬 더 많은 시간을 소비하는 대신 기존의 델타를 버리고 다시 계산합니다.

이것의 효과는 대부분 지속적입니다. 예를 들어, 팩과 헐거운 오브젝트가 서로 결합 될 때 해당 팩의 기존 델타가 재사용 될 수 있지만, 새로운 것에서 차선책을 선택할 수있는 다양한 경우가 있습니다. 대신 팩.

또한 제공 --aggressive하면에 전달 된 --depth--window옵션 이 조정 됩니다 git-repack. 아래 및 설정을
참조하십시오 . 더 큰 창 크기를 사용하면 더 많은 최적의 델타를 찾을 수 있습니다.gc.aggressiveDepthgc.aggressiveWindow

맞춤형 성능 벤치 마크를 실행하지 않고 특정 저장소에서이 옵션을 사용하는 것은 가치가 없을 것 입니다.
훨씬 더 많은 시간이 걸리며 결과적인 공간 / 델타 최적화는 그만한 가치가있을 수도 있고 그렇지 않을 수도 있습니다. 이것을 전혀 사용하지 않는 것은 대부분의 사용자와 해당 저장소에 대한 올바른 절충안입니다.

그리고 ( 080a448 커밋 ) :

gc문서 : --aggressive영향 --window--depth

이후 07e7dbf ( gc: 50 기본 공격 깊이 2016년 8월 11일, 힘내 v2.10.1) 우리는 다소 혼동에서 같은 깊이를 사용하는 --aggressive우리가 기본적으로 할 수있다.

의미가있는 커밋에서 언급했듯이 "공격적"에 대해 더 깊이를 기본값으로 설정하여 런타임 성능을 희생하면서 디스크 공간을 절약하는 것은 잘못되었습니다. 이는 일반적으로 "공격적인 gc"를 원하는 사람과 반대입니다. 원합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.