Pomimo faktu, że GIT NIE przechowuje delt plików, czy nadal możesz przywrócić poprzednie wersje plików (nieograniczoną liczbę razy?)

14

Przeczytałem, że Git nie przechowuje delt plików. Jeśli jest to prawda, w jaki sposób obsługuje wycofywanie plików do poprzednich wersji? Jeśli przechowuje cały plik, miejsce w repozytorium na dysku musi wzrosnąć, aby było niemożliwe do zarządzania. Czy Git obsługuje wycofywanie plików i różnic z powrotem do wersji 1? Czy w ogóle obsługuje koncepcję kontroli wersji związaną z plikami? Jest to (uważam) niezbędne dla zrozumienia VCS / DVCS i moich potrzeb. Muszę być w stanie porównać to, co zamierzam sprawdzić z poprzednimi wersjami.

Pete Alvin
źródło

Odpowiedzi:

44

Git sam nie wyrzuca informacji *. Wszystkie poprzednie wersje każdego pliku są zawsze dostępne do przywracania, różnic, inspekcji itp.

Całe drzewo kontra pojedyncze pliki

To, co możesz próbować pogodzić, to pomysł dostępu do starej wersji pojedynczego pliku w porównaniu z faktem, że model historii Gita koncentruje się na całym drzewie. Wersjonowanie całego drzewa wymaga nieco więcej pracy, aby zobaczyć (na przykład) wersję foo.ctakiej, jaka istniała dziesięć foo.c-zmian temu w porównaniu do dziesięciu zmian całego drzewa temu:

# 10 foo.c-changes ago
git show $(git rev-list -n 10 --reverse HEAD -- foo.c | head -1):foo.c

# 10 whole-tree-changes ago
git show HEAD~10:foo.c

Korzyści z orientacji na drzewa, przede wszystkim możliwość przeglądania zatwierdzeń jako jednostki współzależnych zmian dokonanych w różnych częściach całego drzewa, ogólnie znacznie przewyższają dodatkowe pisanie (które można złagodzić za pomocą aliasów, skryptów itp.) I czas pracy procesora spędził na kopaniu przeszłych zobowiązań.

Wydajność magazynowania

Kiedy nowy obiekt (np. Plik z poprzednio niewidoczną zawartością) wchodzi do systemu, jest on zapisywany z kompresją zwykłą (zlib) jako „luźny obiekt”. Kiedy zgromadzi się wystarczająca liczba luźnych obiektów (w zależności od gc.autoopcji konfiguracji lub gdy użytkownik uruchomi git gc lub jedną z komend pakowania niższego poziomu), Git zgromadzi wiele luźnych obiektów w jednym „pliku pakietu”.

Obiekty w pliku paczki mogą być przechowywane jako zwykłe skompresowane dane (tak samo jak luźny obiekt, tylko w pakiecie z innymi obiektami) lub jako skompresowane delty względem jakiegoś innego obiektu. Delty można łączyć ze sobą w konfigurowalne głębokości ( pack.depth) i można je tworzyć z dowolnym odpowiednim obiektem ( pack.windowkontroluje, jak szeroko Git szuka najlepszej bazy delta; wersja historycznie niepowiązanego pliku może być użyta jako baza, jeśli zrobienie tego dałoby dobra kompresja delta). Szerokość geograficzna, jaką konfiguracje głębokości i rozmiaru okna dają silnikowi kompresji delta, często skutkuje lepszą kompresją delty niż prosta kompresja „jedna wersja względem drugiej / poprzedniej wersji poprzedniej wersji”.

Jest to agresywna kompresja delta (w połączeniu z normalną kompresją zlib), która często pozwala repozytorium Git (z pełną historią i nieskompresowanym drzewem roboczym) zajmować mniej miejsca niż pojedyncze pobranie SVN (z nieskompresowanym drzewem roboczym i nieskazitelną kopią).

Zobacz, w jaki sposób Git przechowuje obiekty i The Packfile w Git Community Book . Również git pack-objects podręcznika .

* Możesz powiedzieć Gitowi, że odrzuca zatwierdzenia, „przepisując historię” i komendami takimi jak git reset , ale nawet w takich przypadkach Git „zatrzymuje się” na nowo odrzuconych zatwierdzeniach przez chwilę, na wypadek, gdybyś zdecydował, że ich potrzebujesz. Zobacz: git reflog i git prune .

Chris Johnsen
źródło
3
+1 tylko za ilość i szczegółowość podanych informacji.
Tamara Wijsman,
3
Ponieważ Git używa migawek plików zamiast delt, cofnięcie się w przeszłość jest w rzeczywistości łatwiejsze. Wyobraź sobie, że musisz zobaczyć plik sprzed 20 zatwierdzeń. Z deltami musisz cofnąć 20 zestawów zmian; dzięki migawkom, po prostu chwytasz odpowiednią migawkę. Im dłuższa historia, tym większa przewaga. A jeśli chcesz zobaczyć różnicę między bieżącą wersją a tą, to tylko jedna różnica, zamiast decydować, co zostało zrobione, cofnąć, powtórzyć itp.
Nathan Long,
Chris, chyba dobrze sobie radzisz z wewnętrznymi elementami Gita. Czy jest jakaś szansa, że ​​się na to rzucisz? stackoverflow.com/questions/5176225/…
Nathan Long,
@ChrisJohnsen Pomóż mi to zrozumieć. Czy na podstawie tego, co powiedziałeś, Git może uzyskać podobną (lub lepszą) wydajność przechowywania niż Subversion? Wiem, że jeśli wielokrotnie zatwierdzę plik z niewielkimi zmianami, dane o wartości 1 GB można zapisać w 100 MB. Czy Git może zrobić to samo?
Alireza Noori,
@AlirezaNoori: Wszystko zależy od charakteru danych i przechwyconych zmian (rozmiar pliku, ściśliwość pliku, rozmiar i lokalizacja zmian itp.). Coś takiego z pewnością powinno być możliwe (w zależności od specyfiki). Ogólnie rzecz biorąc, pliki paczek Git mogą czerpać z większego wyboru podstaw do kompresji delty w porównaniu do ściśle odwrotnych chronologicznych delt używanych przez serwery SVN (używane? Nie śledzę rozwoju SVN…). Jeśli masz jakieś konkretne pytanie, zastanów się nad zadaniem nowego pytania, które zawiera wszystkie istotne szczegóły.
Chris Johnsen
1

Można go przeczytać na tej samej stronie:

...

W związku z tym Git nie rejestruje jawnie relacji wersji pliku na żadnym poziomie poniżej drzewa kodu źródłowego.

...

Nieco droższe jest badanie historii zmian pojedynczego pliku niż całego projektu. Aby uzyskać historię zmian wpływających na dany plik, Git musi przejrzeć historię globalną, a następnie ustalić, czy każda zmiana zmodyfikowała ten plik. Ta metoda sprawdzania historii pozwala jednak Gitowi tworzyć z taką samą wydajnością pojedynczą historię pokazującą zmiany w dowolnym zestawie plików. Na przykład podkatalog drzewa źródłowego oraz powiązany globalny plik nagłówka to bardzo częsty przypadek.

...

W ten sposób możesz wrócić do poprzednich wersji pliku i porównać dwa pliki.

Tamara Wijsman
źródło
1

git faktycznie zapisuje delty plików, ale zapisuje je jako deltę całego drzewa plików.

Aby zobaczyć różnice między wersjami, wykonaj jedną z następujących czynności:

  1. git diff - pokazuje różnice między ostatnio zalogowaną wersją a plikami, które zostały zmienione, ale nie zostały git addna nich uruchomione.
  2. git diff --cached - pokazuje różnice między poprzednią wersją a tym, co wszystkie pliki zostały git adduruchomione, ale nie zostały zatwierdzone
  3. git diff commitid - pokazuje różnice między bieżącym katalogiem roboczym a poprzednim zatwierdzeniem, jak określono w pliku commid
  4. git diff commita..commitb - pokazuje różnice między dwoma zatwierdzeniami, a i b. Zatwierdzenia mogą być również symbolicznymi nazwami, takimi jak gałęzie lub tagi.
edgester
źródło
Ta odpowiedź nie jest naprawdę poprawna. Wszystkie te polecenia można zastosować do dowolnego zestawu plików, a także do całego drzewa - wystarczy dodać nazwy plików na końcu ...
naught101 17.04.13