Czy binarny algorytm diff git (delta storage) jest ustandaryzowany?

Git używa kompresji delta do przechowywania obiektów, które są do siebie podobne.

Czy ten algorytm jest standaryzowany i używany również w innych narzędziach? Czy istnieje dokumentacja opisująca format? Czy jest kompatybilny z xdelta / VCDIFF / RFC 3284?

Author: Thilo, 2012-02-28

3 answers

Myślę, że diff algo używany dla pack files był powiązany z jednym z delta encoding tam: początkowo (2005) xdelta , a następnie libXDiff.
Ale potem, jak szczegółowo poniżej, przeniósł się do niestandardowej realizacji.

W każdym razie, jak wspomniano tutaj :

Git usuwa tylko w plikach packfiles.
Ale po wciśnięciu przez SSH git wygeneruje plik pack z commitami druga strona nie mają, a te paczki są cienkie, więc mają też delty... ale zdalna strona dodaje bazy do tych cienkich paczek, czyniąc je samodzielnymi.

(uwaga: tworzenie wielu plików packfile, lub pobieranie informacji w ogromnych plikach packfile jest kosztowne , i wyjaśnia dlaczego git nie radzi sobie dobrze z ogromnymi plikami lub ogromnymi repo.
Zobacz więcej w " git z dużymi plikami")

Ten wątek przypomina nam również:

Faktycznie packfiles i deltification (LibXDiff, a nie xdelta) było, z tego co pamiętam i Rozumiem, pierwotnie ze względu na przepustowość sieci (która jest znacznie droższa niż miejsce na dysku), i wydajność I/O użycia pojedynczego pliku mmapped zamiast bardzo dużej liczby luźnych obiektów.

LibXDiff jest wspomniany w tym 2008 wątku.

Jednak od tego czasu algo ewoluowało, prawdopodobnie w niestandardowym, jak ten 2011 wątek ilustruje, a jako nagłówek diff-delta.c wyróżnia się:

Tak więc, ściśle mówiąc, obecny kod w Git nie przypomina w ogóle kodu libxdiff.
Jednak podstawowy algorytm stojący za obydwoma implementacjami jest taki sam
.
Studiowanie wersji libxdiff jest prawdopodobnie łatwiejsze, aby zrozumieć, jak to działa.

/*
 * diff-delta.c: generate a delta between two buffers
 *
 * This code was greatly inspired by parts of LibXDiff from Davide Libenzi
 * http://www.xmailserver.org/xdiff-lib.html
 *
 * Rewritten for GIT by Nicolas Pitre <[email protected]>, (C) 2005-2007
 */

Więcej o packfiles the Git Book :

format packfile


Git 2.18 dodaje do opisu delty w nowej sekcji dokumentacja , która obecnie (II kwartał 2018) stwierdza:

Typy obiektów

Poprawne typy obiektów to:

  • OBJ_COMMIT (1)
  • OBJ_TREE (2)
  • OBJ_BLOB (3)
  • OBJ_TAG (4)
  • OBJ_OFS_DELTA (6)
  • OBJ_REF_DELTA (7)

Typ 5 jest zarezerwowany dla przyszłej rozbudowy. Typ 0 jest nieprawidłowy.

Reprezentacja Deltyfikowana

Koncepcyjnie istnieją tylko cztery typy obiektów: commit, tree, tag i blob.
jednak aby zaoszczędzić miejsce, obiekt może być przechowywany jako" delta" kolejny obiekt "bazowy".
Reprezentacje te mają przypisane nowe typy s-delta i ref-delta, które są ważne tylko w pliku pack.

Zarówno ofs-delta jak i ref-delta przechowują "deltę", która ma być zastosowana do inny obiekt (zwany "obiektem bazowym") do rekonstrukcji obiektu.
Różnica między nimi wynosi,

  • ref-delta bezpośrednio koduje 20-bajtową nazwę obiektu bazowego.
    • jeśli obiekt bazowy znajduje się w tym samym pakiecie, ofs-delta koduje przesunięcie obiektu bazowego w pakiecie.

Obiekt bazowy może być również deltyfikowany, jeśli znajduje się w tym samym opakowaniu.
Ref-delta może również odnosić się do obiektu spoza pakietu (tj. tak zwane "cienkie opakowanie") . W przypadku przechowywania na dysku należy jednak być samodzielnym, aby uniknąć cyklicznego zależność.

Dane delta to sekwencja instrukcji do rekonstrukcji obiektu z obiektu podstawowego.
Jeśli obiekt bazowy jest deltyfikowany, musi być najpierw przekonwertowany do postaci kanonicznej. Każda instrukcja dołącza coraz więcej danych do obiektu docelowego, dopóki nie zostanie ukończona.
Do tej pory istnieją dwie obsługiwane instrukcje:

  • jeden do kopiowania zakresu bajtów z obiektu źródłowego i
  • jeden do wstawiania nowych danych osadzonych w Instrukcja sama w sobie.

Każda instrukcja ma zmienną długość. Określa się Typ instrukcji do siódmego bitu pierwszego oktetu. Następujące diagramy Konwencja w RFC 1951 (Deflate compressed data format).

 67
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-23 20:07:07

Kodowanie Git delta jest oparte na copy / insert.

Oznacza to, że plik Pochodny jest zakodowany jako sekwencja opcodów, które mogą reprezentować kopię instrukcje (np.: kopiowanie z pliku podstawowego y bajtów począwszy od offsetu x do bufora docelowego) lub Wstaw instrukcje (np.: Wstaw następne x bajty do docelowego bufora).

Jako bardzo prosty przykład(zaczerpnięty z artykułu 'Obsługa systemu plików dla kompresji Delta'), rozważmy, że chcemy utworzyć bufor delta w celu przekształcenia tekstu "proxy cache" do "proxy pamięci podręcznej". Wynik instrukcji powinien być:

  1. skopiuj 5 bajtów z offsetu 7 (skopiuj 'cache' z bufora bazowego)
  2. Wstaw dwa spacje
  3. skopiuj 5 bajtów z offsetu 0 (skopiuj 'proxy' z bufora bazowego)

Które przetłumaczone na kodowanie git staje się:

(bajty 1-3 reprezentują pierwszą instrukcję)

  • 0x91 (10010001), który dzieli się na
    • 0x80 (10000000) (najbardziej znaczący zestaw bitów sprawia, że jest to ' kopia z base to output ' instruction)
    • 0x01 (00000001) (oznacza 'przesuń o jeden bajt i użyj go jako przesunięcia bazowego)
    • 0x10(00010000) (przesuń o jeden bajt i użyj go jako długości)
  • 0x07 (offset)
  • 0x05 (długość)

(bajty 4-6 reprezentują drugą instrukcję)

  • 0x02 (ponieważ MSB nie jest ustawione, oznacza to 'Wstaw dwa następne bajty do wyjścia')
  • 0x20 (spacja)
  • 0x20 (spacja)

(bajty 7-8 reprezentują ostatnią Instrukcja)

  • 0x90 (10010000), który dzieli się na
    • 0x80 (10000000) (oznacza "kopię")
    • 0x10(00010000) (przesuń o jeden bajt i użyj go jako długości)
  • 0x05 (długość)

Zauważ, że w ostatniej instrukcji kopiowania Nie podano offsetu, co oznacza offset 0. Pozostałe bity w kopii można również ustawić kod opcode, gdy potrzebne są większe przesunięcia/długości.

Wynik bufora delta ma w tym przykładzie 8 bajtów, co nie jest kompresja ponieważ bufor docelowy ma 12 bajtów, ale gdy kodowanie to stosuje się do dużych plików tekstowych, może zrób wielką różnicę.

Ostatnio wypchnąłem węzeł.biblioteka js do github który implementuje obie funkcje diff/patch używając kodowania Git delta. Na Kod powinien być bardziej czytelny i skomentował niż ten w git source, który jest mocno zoptymalizowany.

Napisałem też kilka testy które wyjaśniają wyjściowych opcodów użytych w każdym przykład w formacie podobnym do powyższego.

 25
Author: Thiago de Arruda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-13 13:55:35

Czy ten algorytm jest znormalizowany i używany również w innych narzędziach?

Format pack jest częścią publicznego API: protokoły transferu używane do operacji push i fetch używają go do wysyłania mniejszej ilości danych przez sieć.

Są one zaimplementowane w co najmniej dwóch innych głównych implementacjach Gita oprócz referencji: JGiti libgit2.

Dlatego jest bardzo mało prawdopodobne, aby nastąpiły wstecznie niezgodne zmiany w formacie i mogą być uważany za "znormalizowany" w tym sensie.

Ten niesamowity Plik z docs opisuje heurystykę używaną w algorytmie pack jako zabawny komentarz do e-maila Linusa: https://github.com/git/git/blob/v2.9.1/Documentation/technical/pack-heuristics.txt

 5
Author: Ciro Santilli TRUMP BAN IS BAD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:14