Linus zasugerował (zobacz poniżej pełny post na liście mailingowej), używając go git gc --aggressive
tylko wtedy, gdy masz, jego słowami, „ naprawdę zły pakiet” lub „naprawdę strasznie złe delty”, jednak „prawie zawsze, w innych przypadkach jest to naprawdę bardzo złe rzecz do zrobienia." Rezultat może nawet pozostawić repozytorium w gorszym stanie niż na początku!
Polecenie, które sugeruje, aby zrobić to właściwie po zaimportowaniu „długiej i zawiłej historii”, brzmi
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: <[email protected]>
Message-ID: <[email protected]>
References: <[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
W czwartek, 6 grudnia 2007, Daniel Berlin napisał:
Właściwie okazuje się, że git-gc --aggressive
czasami pakuje się pliki, niezależnie od tego, czy dokonałeś konwersji z repozytorium SVN, czy nie.
Absolutnie. git --aggressive
jest przeważnie głupi. Jest to przydatne tylko w przypadku „Wiem, że mam naprawdę kiepski pakiet i chcę odrzucić wszystkie złe decyzje dotyczące pakowania”.
Aby to wyjaśnić, warto wyjaśnić (prawdopodobnie jesteś tego świadomy, ale i tak przejdę przez podstawy), jak działają łańcuchy delta git i jak bardzo różnią się od większości innych systemów.
W innych SCM łańcuch delta jest zwykle naprawiony. Może to być „do przodu” lub „do tyłu” i może ewoluować nieco podczas pracy z repozytorium, ale ogólnie jest to łańcuch zmian w pojedynczym pliku reprezentowanym jako pewnego rodzaju pojedynczy obiekt SCM. W CVS jest to oczywiście *,v
plik, a wiele innych systemów robi raczej podobne rzeczy.
Git również obsługuje łańcuchy delta, ale robi to dużo bardziej „luźno”. Nie ma stałej jednostki. Różnice są generowane dla dowolnej innej losowej wersji, którą git uważa za dobrego kandydata na deltę (z różnymi dość skutecznymi heurystykami) i nie ma absolutnie żadnych twardych reguł grupowania.
Generalnie jest to bardzo dobra rzecz. Jest to dobre z różnych powodów koncepcyjnych ( np. Git wewnętrznie nigdy nie musi nawet przejmować się całym łańcuchem wersji - tak naprawdę nie myśli w kategoriach delt), ale jest również świetny, ponieważ pozbycie się nieelastycznych reguł delta oznacza że git nie ma żadnych problemów ze scalaniem dwóch plików, na przykład - po prostu nie ma żadnych *,v
„plików wersji”, które mają jakieś ukryte znaczenie.
Oznacza to również, że wybór delt jest kwestią znacznie bardziej otwartą. Jeśli ograniczysz łańcuch delta do tylko jednego pliku, naprawdę nie masz dużego wyboru, co zrobić z deltami, ale w git naprawdę może to być zupełnie inny problem.
I tu pojawia się naprawdę źle nazwany --aggressive
. Chociaż git generalnie próbuje ponownie wykorzystać informacje delta (ponieważ jest to dobry pomysł i nie marnuje czasu procesora na ponowne znajdowanie wszystkich dobrych delt, które znaleźliśmy wcześniej), czasami chcesz powiedzieć „zacznijmy wszystko od nowa, z pustą planszą, zignoruj wszystkie poprzednie informacje o różnicach i spróbuj wygenerować nowy zestaw delt”.
Tak --aggressive
naprawdę nie chodzi o bycie agresywnym, ale o marnowanie czasu procesora na ponowne podejmowanie decyzji, którą już podjęliśmy wcześniej!
Czasami to dobrze. W szczególności niektóre narzędzia do importowania mogą generować naprawdę strasznie złe delty. Wszystko, co używagit fast-import
, prawdopodobnie nie ma świetnego układu delta, więc warto powiedzieć: „Chcę zacząć od czystej karty”.
Ale prawie zawsze, w innych przypadkach, jest to naprawdę złe. Spowoduje to stratę czasu procesora, a zwłaszcza jeśli wcześniej wykonałeś dobrą robotę przy deltaowaniu, wynik końcowy nie będzie ponownie wykorzystywał wszystkich dobrych delt, które już znalazłeś, więc tak naprawdę skończysz z dużo gorszy wynik końcowy!
Wyślę łatkę do Junio, aby po prostu usunąć git gc --aggressive
dokumentację. Może być przydatna, ale generalnie jest przydatna tylko wtedy, gdy naprawdę rozumiesz, na bardzo głębokim poziomie, co robi, a ta dokumentacja ci w tym nie pomaga.
Generalnie robienie przyrostowe git gc
jest właściwym podejściem i jest lepsze niż robienie git gc --aggressive
. Będzie ponownie używać starych delt, a kiedy nie można ich znaleźć (powód wykonywania przyrostowych GC w pierwszej kolejności!), Utworzy nowe.
Z drugiej strony, z pewnością prawdą jest, że „początkowy import długiej i zawiłej historii” to moment, w którym warto poświęcić dużo czasu na znalezienie naprawdę dobrych delt. Wtedy każdy użytkownik kiedykolwiek (o ile nie użyje go git gc --aggressive
do cofnięcia!) Otrzyma korzyść z tego jednorazowego zdarzenia. Dlatego szczególnie w przypadku dużych projektów z długą historią, prawdopodobnie warto wykonać dodatkową pracę, nakazując kodowi znajdującemu delta oszaleć.
Tak więc odpowiednikiem git gc --aggressive
- ale wykonanym prawidłowo - jest zrobienie (z dnia na dzień) czegoś takiego
git repack -a -d --depth=250 --window=250
gdzie ta kwestia głębi dotyczy tego, jak głębokie mogą być łańcuchy delta (wydłuż je dla starej historii - jest to warte przestrzeni narzutu), a sprawa okna dotyczy tego, jak duże okno obiektu chcemy przeskanować każdy kandydat na deltę.
I tutaj możesz chcieć dodać -f
flagę (która oznacza „porzucić wszystkie stare delty”, ponieważ teraz faktycznie próbujesz upewnić się, że ta faktycznie znajduje dobrych kandydatów.
A potem zajmie to wieczność i jeden dzień ( czyli „zrób to z dnia na dzień”). Ale końcowy rezultat jest taki, że wszyscy poniżej tego repozytorium otrzymają znacznie lepsze pakiety, bez konieczności poświęcania na to żadnego wysiłku.
Linus
Jak wspomniałem w artykule „ Git Garbage Collection nie wydaje się w pełni działać ”, sam a
git gc --aggressive
nie jest ani wystarczający, ani nawet wystarczający.I, jak wyjaśnię poniżej , często nie są potrzebne.
Najskuteczniejszą kombinacją byłoby dodanie
git repack
, ale takżegit prune
:Uwaga: Git 2.11 (Q4 2016) ustawi domyślną
gc aggressive
głębokość na 50Zobacz commit 07e7dbf (11 sierpnia 2016) autorstwa Jeffa Kinga (
peff
) .(Scalone przez Junio C Hamano -
gitster
- w zobowiązaniu 0952ca8 , 21 września 2016 r.)(Zobacz zobowiązanie do nauki )
Mówiąc o oszczędzaniu procesora, "
git repack
" nauczył się akceptować--threads=<n>
opcję i przekazywać ją do obiektów paczki.Zobacz commit 40bcf31 (26 kwietnia 2017) autorstwa Junio C Hamano (
gitster
) .(Scalenie przez Junio C Hamano -
gitster
- w zatwierdzeniu 31fb6f4 , 29 maja 2017)Robimy to już dla
--window=<n>
i--depth=<n>
; pomoże to, gdy użytkownik chce wymusić--threads=1
powtarzalne testy bez wpływu na wyścigi wielu wątków.źródło
git gc --aggressive
zostało to naprawione dwukrotnie: po pierwsze, aby zrobić to, co Linus zasugerował w 2007 roku jako „lepszą metodę pakowania”. A potem w Git 2.11, aby uniknąć nadmiernej głębokości obiektów, którą zasugerował Linus, ale która okazała się szkodliwa (spowalnia wszystkie przyszłe operacje Gita i nie oszczędza miejsca, o którym warto mówić).man git-repack
mówi dla-d
: `Uruchom także git prune -pack, aby usunąć zbędne luźne pliki obiektowe. 'Czygit prune
też robi to?man git-prune
mówiIn most cases, users should run git gc, which calls git prune.
, więc po co to wszystkogit gc
? Czy nie byłoby lepiej lub wystarczy użyć tylkogit repack -Ad && git gc
?Problem z
git gc --aggressive
polega na tym, że nazwa opcji i dokumentacja są mylące.Jak sam Linus wyjaśnia w tym mailu ,
git gc --aggressive
zasadniczo robi to:Zwykle nie ma potrzeby ponownego obliczania delt w git, ponieważ git określa te delty bardzo elastycznie. Ma to sens tylko wtedy, gdy wiesz, że masz naprawdę, naprawdę złe delty. Jak wyjaśnia Linus, głównie narzędzia, które wykorzystują
git fast-import
do tej kategorii należą .W większości przypadków git wykonuje całkiem niezłą robotę przy określaniu użytecznych delt, a używanie
git gc --aggressive
pozostawi delty, które są potencjalnie nawet gorsze, a jednocześnie marnują dużo czasu procesora.Linus kończy swój list wnioskiem, że
git repack
z dużym--depth
i--window
jest lepszym wyborem w większości przypadków; szczególnie po zaimportowaniu dużego projektu i chcesz się upewnić, że git znajdzie dobre delty.źródło
Uwaga. Nie uruchamiaj
git gc --agressive
z repozytorium, które nie jest zsynchronizowane ze zdalnym, jeśli nie masz kopii zapasowych.Ta operacja odtwarza delty od zera i może doprowadzić do utraty danych, jeśli zostanie bezpiecznie przerwana.
Na moim komputerze z 8 GB agresywnego gc zabrakło pamięci w repozytorium 1 GB z 10 000 małymi zatwierdzeniami. Kiedy OOM killer zakończył proces gita - zostawił mnie z prawie pustym repozytorium, przetrwało tylko działające drzewo i kilka delt.
Oczywiście nie była to jedyna kopia repozytorium, więc po prostu ją odtworzyłem i ściągnąłem ze zdalnego (pobieranie nie działało na zepsutym repozytorium i zablokowało się na kroku `` rozwiązywania delt '' kilka razy próbowałem to zrobić), ale jeśli twoje repozytorium jest Lokalne repozytorium jednego programisty bez pilotów - najpierw wykonaj kopię zapasową.
źródło
Uwaga: uważaj na używanie
git gc --aggressive
, jak wyjaśnia Git 2.22 (Q2 2019).Zobacz zatwierdzenie 0044f77 , zatwierdzenie daecbf2 , zatwierdzenie 7384504 , zatwierdzenie 22d4e3b , zatwierdzenie 080a448 , zatwierdzenie 54d56f5 , zatwierdzenie d257e0f , zatwierdzenie b6a8d09 (07 kwietnia 2019) i zatwierdzenie fc559fb , zatwierdzenie cf9cd77 , zatwierdzenie b11e856 (22 marca 2019) do (Börjarm
avar
) do (Börjarm ) .(Scalone przez Junio C Hamano -
gitster
- w zobowiązaniu ac70c53 , 25 kwietnia 2019 r.)Oznacza to, że dokumentacja git-gc zawiera teraz :
Oraz ( zatwierdzenie 080a448 ):
źródło