Background maintenance i nie tylko.
git maintenance
Wyobraź sobie to: jesteś w terminalu, piszesz commity, pobierasz zmiany z innego repozytorium i pushujesz na serwer, gdy nagle wita Cię ta nieprzyjazna wiadomość:
Auto packing the repository for optimum performance. You may also
run "git gc" manually. See "git help gc" for more information.
I stoisz w miejscu. Teraz musisz poczekać, aż Git zakończy działanie git gc –auto
, zanim będziesz mógł wrócić do pracy.
Co tu się stało? W trakcie normalnego użytkowania Git zapisuje wiele danych: obiekty, pliki pakietów, referencje itp. Niektóre z tych ścieżek są zoptymalizowane pod kątem wydajności zapisu. Na przykład znacznie szybciej można zapisać pojedynczy, „luźny” obiekt, ale szybciej jest odczytać cały packfile. Aby nie wstrzymywać Twojej pracy, Git dokonuje kompromisu: generalnie optymalizuje ścieżkę zapisu podczas pracy, zatrzymując się jednak co jakiś czas, aby przedstawić swoje wewnętrzne struktury danych w sposób bardziej efektywny do odczytu.
Git ma swoją własną heurystykę dotyczącą tego, kiedy jest dobry moment na wykonanie tej „pauzy”, ale czasami te heurystyki wyzwalają blokujący Cię git gc
w najgorszym możliwym momencie. Oczywiście możesz samodzielnie zarządzać tymi strukturami danych, ale raczej nie będziesz chciał poświęcać czasu na zastanawianie się, kiedy i jak to zrobić.
Począwszy od Git 2.31, można uzyskać to, co najlepsze z obu światów dzięki background maintenance
. Ta wieloplatformowa funkcja umożliwia Gitowi utrzymanie dobrego stanu repozytorium, nie blokując żadnych interakcji. W szczególności poprawi to czasy wykonywania git fetch
, pobierając z wyprzedzeniem najnowsze pliki ze zdalnych repozytoriów raz na godzinę.
Rozpoczęcie pracy z tą „konserwacją w tle” nie może być prostsze. Po prostu przejdź do dowolnego repozytorium, w którym chcesz włączyć obsługę w tle, i wykonaj:
$ git maintenance start
Git zajmie się resztą. Oprócz wstępnego pobierania najnowszych plików raz na godzinę, Git upewni się, że jego własne dane są również uporządkowane. Będzie aktualizować swój commit-graph
raz na godzinę i co noc pakować wszelkie luźne pliki (a także stopniowo przepakowywać spakowane już obiekty).
Nową funkcję można też dostosować do swoich potrzeb za pomocą opcji w configach maintenance.*
.
Dyskowe indeksy zwrotne
Być może wiesz, że Git przechowuje wszystkie dane jako wspominane już w tym artykule „obiekty”: commits, trees i blobs, które przechowują zawartość poszczególnych plików. Aby zwiększyć wydajność, Git umieszcza wiele obiektów w plikach packfiles, które są zasadniczo połączonym strumieniem obiektów (ten sam strumień jest również sposobem przesyłania obiektów przez git fetch
i git push
). Aby efektywnie uzyskać dostęp do poszczególnych obiektów, Git generuje indeks dla każdego pliku pakietu. Każdy z tych plików .idx umożliwia szybką konwersję identyfikatora obiektu na jego offset bajtowy w pliku pakietu.
Sprawdź oferty pracy na TeamQuest
Skąd Git wie którego obiektu dotyczy bajt, którego właśnie szuka w jakimś packfile? Aby to osiągnąć, Git używa mapowania reverse index. Przed Git 2.31 nie było formatu na dysku dla indeksów odwrotnych (jak w przypadku pliku .idx), więc za każdym razem musiał on generować i przechowywać indeks odwrotny w pamięci. Z grubsza sprowadza się to do wygenerowania tablicy par obiekt-pozycja, a następnie posortowania tej tablicy według pozycji. Ale to wymaga czasu. W przypadku repozytoriów z dużymi plikami packfiles może to zająć dużo czasu.
W wersji 2.31 Git zyskał możliwość serializacji indeksu wstecznego do nowego formatu na dysku z rozszerzeniem .rev
. Póki co Git nie generuje jeszcze domyślnie plików .rev ale możesz poeksperymentować z nimi samodzielnie, uruchamiając git config pack.writeReverseIndex true
, a następnie przepakowując repozytorium (za pomocą git repack -Ad
).