Co dokładnie zawiera indeks git?

178

Co dokładnie zawiera indeks Git i jakiego polecenia mogę użyć, aby wyświetlić zawartość indeksu?


Aktualizacja

Dzięki za wszystkie odpowiedzi. Wiem, że indeks działa jako obszar przemieszczania, a to, co jest zatwierdzane, znajduje się w indeksie, a nie w drzewie roboczym. Jestem po prostu ciekawy, z czego składa się obiekt indeksu. Myślę, że może to być lista nazwa pliku / nazwa katalogu, pary SHA-1, może rodzaj wirtualnego drzewa?

Czy w terminologii Git jest jakieś polecenie hydrauliczne , którego mogę użyć do wyświetlenia zawartości indeksu?

mochidino
źródło
3
powinieneś przeczytać i obejrzeć diagramy - bardzo pomocne: gitguys.com/topics/whats-the-deal-with-the-git-index
kernix
1
@kernix domena wygasła. Nie jest już zbyt pomocny.
narendra-choudhary

Odpowiedzi:

162

Książka Git zawiera artykuł o tym, co zawiera indeks :

Indeks jest plikiem binarnym (zwykle przechowywanym w .git/index) zawierającym posortowaną listę nazw ścieżek, z których każda ma uprawnienia i SHA1 obiektu blob; git ls-filesmoże pokazać zawartość indeksu:

$ git ls-files --stage
100644 63c918c667fa005ff12ad89437f2fdc80926e21c 0   .gitignore
100644 5529b198e8d14decbe4ad99db3f7fb632de0439d 0   .mailmap

Problem Racy git podaje więcej szczegółów na temat tej struktury:

Indeks jest jedną z najważniejszych struktur danych w git.
Reprezentuje stan wirtualnego drzewa roboczego poprzez rejestrowanie listy ścieżek i nazw ich obiektów i służy jako obszar pomostowy do zapisania następnego obiektu drzewa do zatwierdzenia.
Stan jest „wirtualny” w tym sensie, że niekoniecznie musi, a często nie, zgadza się z plikami w drzewie roboczym.


Aby zobaczyć więcej, por. „ git / git / Documentation / technical / index-format.txt ”:

Plik indeksu Git ma następujący format

Wszystkie liczby binarne są w sieciowej kolejności bajtów.
Wersja 2 jest opisana tutaj, chyba że określono inaczej.

  • 12-bajtowy nagłówek składający się z:
    • Podpis 4-bajtowy :
      podpis to {' D', ' I', ' R', ' C'} (oznacza „ dircache”)
    • 4-bajtowy numer wersji :
      Aktualnie obsługiwane wersje to 2, 3 i 4.
    • 32-bitowa liczba pozycji indeksu.
  • Liczba posortowanych pozycji indeksu .
  • Rozszerzenia :
    rozszerzenia są identyfikowane za pomocą podpisu.
    Opcjonalne rozszerzenia można zignorować, jeśli Git ich nie rozumie.
    Obecnie Git obsługuje buforowane drzewo i rozwiązuje cofanie rozszerzeń.
    • 4-bajtowy podpis rozszerzenia. Jeśli pierwszy bajt to „ A…” Z, rozszerzenie jest opcjonalne i można je zignorować.
    • 32-bitowy rozmiar rozszerzenia
    • Dane rozszerzenia
  • 160-bitowe SHA-1 nad zawartością pliku indeksu przed tą sumą kontrolną.

mljrg komentarze :

Jeśli indeks jest miejscem, w którym przygotowywana jest następna rewizja, dlaczego " git ls-files -s" nic nie zwraca po zatwierdzeniu?

Ponieważ indeks reprezentuje to, co jest śledzone , a tuż po zatwierdzeniu, to, co jest śledzone, jest identyczne z ostatnim zatwierdzeniem ( git diff --cachednic nie zwraca).

Tak więc git ls-files -swyświetla wszystkie śledzone pliki (nazwa obiektu, bity trybu i numer etapu na wyjściu).

Ta lista (śledzonych elementów) jest inicjowana treścią zatwierdzenia.
Po przełączeniu gałęzi zawartość indeksu jest resetowana do zatwierdzenia, do którego odwołuje się gałąź, do której właśnie się przełączyłeś.


Git 2.20 (Q4 2018) dodaje tabelę przesunięć indeksu (IEOT) :

Zobacz: commit 77ff112 , commit 3255089 , commit abb4bb8 , commit c780b9c , commit 3b1d9e0 , commit 371ed0d (10 października 2018) przez Ben Peart ( benpeart) .
Zobacz commit 252d079 (26 września 2018) autorstwa Nguyễn Thái Ngọc Duy ( pclouds) .
(Scalone przez Junio ​​C Hamano - gitster- in commit e27bfaa , 19 października 2018)

ieot: dodaj rozszerzenie Index Entry Offset Table (IEOT)

Ta poprawka umożliwia zajęcie się kosztem CPU ładowania indeksu przez dodanie dodatkowych danych do indeksu, które pozwolą nam wydajnie wielowątkowe ładowanie i konwersję wpisów pamięci podręcznej.

Osiąga to poprzez dodanie (opcjonalnego) rozszerzenia indeksu, które jest tabelą offsetów do bloków wpisów pamięci podręcznej w pliku indeksu.

Aby to działało dla indeksów V4, podczas zapisywania wpisów w pamięci podręcznej okresowo „resetuje” kompresję prefiksu, kodując bieżący wpis, tak jakby nazwa ścieżki dla poprzedniego wpisu była zupełnie inna i zapisuje przesunięcie tego wpisu w IEOT .
Zasadniczo w przypadku indeksów V4 generuje przesunięcia w blokach wpisów skompresowanych przedrostkami.

Dzięki nowemu ustawieniu konfiguracji index.threads ładowanie indeksu jest teraz szybsze.


W rezultacie ( używając IEOT ), 7bd9631 oczyści read-cache.c load_cache_entries_threaded()funkcję dla Git 2.23 (Q3 2019).

Zobacz popełnić 8373037 , popełnić d713e88 , popełnić d92349d , popełnić 113c29a , popełnić c95fc72 , popełnić 7a2a721 , popełnić c016579 , popełnić be27fb7 , popełnić 13a1781 , popełnić 7bd9631 , popełnić 3c1dce8 , popełnić cf7a901 , popełnić d64db5b , popełnić 76a7bc0 (09 maja 2019) przez Jeffa Kinga ( peff) .
(Scalone przez Junio ​​C Hamano - gitster- w zatwierdzeniu c0e78f7 , 13 czerwca 2019 r.)

read-cache: usuń nieużywany parametr z ładowania wątkowego

load_cache_entries_threaded()Funkcja przyjmuje src_offsetparametr, który nie używa. Tak było od jego powstania w 77ff112 ( read-cache: ładowanie wpisów pamięci podręcznej wątków roboczych, 2018-10-10, Git v2.20.0-rc0).

Kopiąc na liście mailingowej, parametr ten był częścią wcześniejszej iteracji serii , ale stał się niepotrzebny, gdy kod został przełączony na korzystanie z rozszerzenia IEOT.

VonC
źródło
6
O tym, jakie znaczenie ma indeks w modelu Git, patrz stackoverflow.com/questions/1450348/ ...
VonC
Pierwszy link powyżej wskazuje na wersję git-scm, która nie ma artykułu w indeksie. Myślę, że intencją było wskazanie tutaj: schacon.github.io/gitbook/7_the_git_index.html
Kris Giesing
1
@KrisGiesing Dziękuję za link. Zaktualizowałem odpowiedź.
VonC
@VonC Jeśli indeks jest miejscem, w którym przygotowywane jest następne zatwierdzenie, dlaczego „git ls-files -s” nie zwraca niczego po zatwierdzeniu? W indeksie musi być coś więcej, niż umieściłeś w swojej odpowiedzi.
mljrg
@mljrg nie jestem pewien, czy podążam za tobą: po zatwierdzeniu etap (na którym przygotowywano zatwierdzenie) byłby pusty, ponieważ zatwierdzenie zostało wykonane, prawda?
VonC
62

Analiza krok po kroku

Postanowiłem zrobić małe testy, aby lepiej zrozumieć format i bardziej szczegółowo zbadać niektóre pola.

Wyniki poniżej są takie same dla wersji Git 1.8.5.2i 2.3.

Oznaczyłem punkty, których nie jestem pewien / których nie znalazłem TODO: prosimy o uzupełnienie tych punktów.

Jak wspominali inni, indeks jest przechowywany pod .git/index, a nie jako standardowy obiekt drzewa, a jego format jest binarny i udokumentowany pod adresem : https://github.com/git/git/blob/master/Documentation/technical/index-format. tekst

Główne struktury, które definiują indeks, znajdują się w pliku cache.h , ponieważ indeks jest pamięcią podręczną do tworzenia zatwierdzeń.

Ustawiać

Kiedy zaczynamy repozytorium testowe z:

git init
echo a > b
git add b
tree --charset=ascii

Na .gitwygląd katalogu lubię:

.git/objects/
|-- 78
|   `-- 981922613b2afb6025042ff6bd878ac1994e85
|-- info
`-- pack

A jeśli otrzymamy zawartość jedynego obiektu:

git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85

Dostajemy a. Oznacza to, że:

  • te indexpunkty do zawartości plików, ponieważ git add bstworzył obiekt blob
  • przechowuje metadane w pliku indeksu, a nie w obiekcie drzewa, ponieważ był tylko jeden obiekt: blob (na zwykłych obiektach Git metadane bloba są przechowywane w drzewie)

analiza hd

Spójrzmy teraz na sam indeks:

hd .git/index

Daje:

00000000  44 49 52 43 00 00 00 02  00 00 00 01 54 09 76 e6  |DIRC.... ....T.v.|
00000010  1d 81 6f c6 54 09 76 e6  1d 81 6f c6 00 00 08 05  |..o.T.v. ..o.....|
00000020  00 e4 2e 76 00 00 81 a4  00 00 03 e8 00 00 03 e8  |...v.... ........|
00000030  00 00 00 02 78 98 19 22  61 3b 2a fb 60 25 04 2f  |....x.." a;*.`%./|
00000040  f6 bd 87 8a c1 99 4e 85  00 01 62 00 ee 33 c0 3a  |......N. ..b..3.:|
00000050  be 41 4b 1f d7 1d 33 a9  da d4 93 9a 09 ab 49 94  |.AK...3. ......I.|
00000060

Następnie podsumujemy:

  | 0           | 4            | 8           | C              |
  |-------------|--------------|-------------|----------------|
0 | DIRC        | Version      | File count  | ctime       ...| 0
  | ...         | mtime                      | device         |
2 | inode       | mode         | UID         | GID            | 2
  | File size   | Entry SHA-1                              ...|
4 | ...                        | Flags       | Index SHA-1 ...| 4
  | ...                                                       |

Najpierw nagłówek, zdefiniowany pod adresem: struct cache_header :

  • 44 49 52 43: DIRC. DO ZROBIENIA: dlaczego jest to konieczne?

  • 00 00 00 02: wersja formatu: 2. Format indeksu ewoluował z czasem. Obecnie istnieje wersja do 4. Format indeksu nie powinien stanowić problemu podczas współpracy między różnymi komputerami na GitHub, ponieważ puste repozytoria nie przechowują indeksu: jest on generowany w czasie klonowania.

  • 00 00 00 01Count plików na index: tylko jeden, b.

Następnie rozpoczyna listę wpisów indeksu, zdefiniowaną przez struct cache_entry Tutaj mamy tylko jeden. Zawiera:

  • zbiór metadanych plików: 8 bajtów ctime, 8 bajtów mtime, a następnie 4 bajty: urządzenie, i-węzeł, tryb, UID i GID.

    Zwróć uwagę, jak:

    • ctimei mtimesą takie same (54 09 76 e6 1d 81 6f c6 ), jak oczekiwano, ponieważ nie zmodyfikowaliśmy pliku

      Pierwsze bajty to sekundy od EPOCH w formacie szesnastkowym:

      date --date="@$(printf "%x" "540976e6")"
      

      Daje:

      Fri Sep  5 10:40:06 CEST 2014
      

      I wtedy zrobiłem ten przykład.

      Drugie 4 bajty to nanosekundy.

    • UID i GID to 00 00 03 e81000 szesnastkowo: typowa wartość dla konfiguracji jednego użytkownika.

    Wszystkie te metadane, z których większość nie występuje w obiektach drzewa, pozwalają Gitowi sprawdzić, czy plik szybko się zmienił, bez porównywania całej zawartości.

  • na początku linii 30: 00 00 00 02: rozmiar pliku: 2 bajty ( ai \nod echo)

  • 78 98 19 22 ... c1 99 4e 85: 20 bajtów SHA-1 w stosunku do poprzedniej treści wpisu. Zauważ, że zgodnie z moimi eksperymentami z zakładaną poprawną flagą , flagi, które po niej występują, nie są uwzględniane w tym SHA-1.

  • Flagi 2-bajtowe: 00 01

    • 1 bit: załóż poprawną flagę. Moje badania wskazują, że ta źle nazwana flaga jest miejscem, w którym git update-index --assume-unchangedprzechowuje swój stan: https://stackoverflow.com/a/28657085/895245

    • 1-bitowa rozszerzona flaga. Określa, czy rozszerzone flagi są obecne, czy nie. Musi być 0w wersji 2, która nie ma rozszerzonych flag.

    • 2-bitowa flaga etapu używana podczas łączenia. Etapy są udokumentowane w man git-merge:

      • 0: zwykły plik, nie w konflikcie scalania
      • 1: baza
      • 2: nasz
      • 3: ich

      Podczas konfliktu scalania wszystkie etapy od 1 do 3 są przechowywane w indeksie, aby umożliwić operacje takie jak git checkout --ours.

      Jeśli tak git add, to do indeksu ścieżki zostanie dodany etap 0, a Git będzie wiedział, że konflikt został oznaczony jako rozwiązany. DO ZROBIENIA: sprawdź to.

    • 12-bitowa długość ścieżki, która będzie następować:: 0 01tylko 1 bajt od początku ścieżkib

  • Rozszerzone flagi 2-bajtowe. Ma znaczenie tylko wtedy, gdy „flaga rozszerzona” została ustawiona na flagach podstawowych. DO ZROBIENIA.

  • 62(ASCII b): ścieżka o zmiennej długości. Długość określona w poprzednich flag, tutaj tylko 1 bajt b.

Następnie pojawia się 00: 1-8 bajtów wypełnienia zerami, tak że ścieżka będzie zakończona znakiem null, a indeks będzie się kończył wielokrotnością 8 bajtów. Dzieje się tak tylko przed wersją indeksu 4.

Nie użyto żadnych rozszerzeń. Git wie o tym, ponieważ w pliku nie byłoby wystarczającej ilości miejsca na sumę kontrolną.

Na koniec znajduje się 20-bajtowa suma kontrolna ee 33 c0 3a .. 09 ab 49 94nad zawartością indeksu.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
1
Bardzo interesujące. +1. To ładnie ilustruje moją własną odpowiedź . Zastanawiam się, czy te wyniki uległyby zmianie w najnowszym Git 2.1+.
VonC
3
@NielsBom tak, to też by działało. Podczas interpretacji programów wolę przyjąć dwa podejścia: najpierw empiryczne, aby zobaczyć, jakie wyniki generuje, a dopiero potem przeczytać źródło. W przeciwnym razie można zostać złapanym w skrajne przypadki kodu źródłowego, które nie pojawiają się nawet na prostych wynikach. Oczywiście przyjrzałem się strukturom źródłowym, aby pomóc mi w prowadzeniu, i każde zadanie TODO można rozwiązać, czytając, jak manipuluje się tymi strukturami, co jest trudną częścią.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: Jeśli zmodyfikuję indeks w edytorze szesnastkowym i zaktualizuję jego 20-bajtową sumę kontrolną, czy istnieje polecenie zaktualizowania sha1, które jest przechowywane w innych obiektach? (git skarży się, że sygnatura indeksu sha1 jest uszkodzona) . Dane indeksu są również przechowywane w zupełnie inny sposób, gdy są wysyłane przez żądania wypychania.
user2284570
1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: Cele bezpieczeństwa. Po prostu szukam dobrze znanego rodzaju ataków na pliki obrazów rastrowych stosowanych do bazy danych / obiektów git. (oczywiście wiem, że większość implementacji zajmowała się ostatnio tą perspektywą, ale prawdopodobnie nie wszystkie)  Więc szczególnie szukam binarnych struktur danych, które mówią o długości tablicy. (w odniesieniu do buforów tekstowych wydaje się, że zerowe zakończenie jest normą
określającą
1
Odnośnie git add, na twoje TODO: masz rację. Jeśli masz pozycje indeksu wysokiego etapu (konflikt) w danej ścieżce, po przejściu do git addtej ścieżki wszystkie pozycje indeksu wysokiego etapu zostaną usunięte, a kopia katalogu roboczego zostanie dodana na etapie 0. (Rozwiązanie konfliktu).
Edward Thomson
11

Indeks Git to obszar przejściowy między katalogiem roboczym a repozytorium. Możesz użyć indeksu do zbudowania zestawu zmian, które chcesz wspólnie zatwierdzić. Kiedy tworzysz zatwierdzenie, zatwierdzane jest to, co aktualnie znajduje się w tym indeksie, a nie to, co jest w katalogu roboczym.

Aby zobaczyć, co jest w indeksie, wydaj polecenie:

git status

Kiedy uruchomisz status git, możesz zobaczyć, które pliki są w fazie przejściowej (obecnie w twoim indeksie), które są zmodyfikowane, ale jeszcze nie są w fazie przemieszczania, a które całkowicie nie są śledzone.

Możesz przeczytać ten . Wyszukiwarka Google generuje wiele linków, które powinny być dość samowystarczalne.

user225312
źródło
7
git statusnie wyświetla wszystkich plików z indeksu. Zawiera tylko te pliki, które różnią się między indeksem a katalogiem roboczym. Aby zobaczyć wszystkie pliki w indeksie, musisz użyć git ls-files.
Akash Agrawal
1
@AkashAgrawal, git status robi się lista plików indeksowych fakt, niezależnie od tego, czy różnią się one między indeksem i WORKDIR.
Acumenus
3
tak, wymienia NIEKTÓRE pliki indeksu, ale nie pokazuje wszystkiego, co jest w indeksie, o czym mówi jego stwierdzenie w jego odpowiedzi. To tak, jakby powiedzieć, że w pudełku są 2 zielone kule i 3 czerwone kule. Aby zobaczyć, co jest w pudełku, wyciągnij 2 zielone kulki. To, co powiedział Akash, jest najdokładniejsze, aby zobaczyć wszystkie pliki w indeksie, użyj git ls-files.
dave4jr
3
W rzeczy samej. git statuswyświetla listę plików znajdujących się w indeksie, tak, ale nie wyświetla wszystkich plików w indeksie. Wyjaśnienie, jak git status faktycznie działa, byłoby korzystną odpowiedzią na pewne pytanie, choć prawdopodobnie nie na to.
Edward Thomson,
1
git statuspokazuje stan drzewa roboczego (różnica między drzewem roboczym a indeksem). W rzeczywistości nie pokazuje indeksu. git-scm.com/docs/git-status
wisbucky
1

Oto, czego dokładnie potrzebujesz, użyj tego polecenia.

$ binwalk index

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1717          0x6B5           Unix path: /company/user/user/delete.php
1813          0x715           Unix path: /company/user/user/get.php
1909          0x775           Unix path: /company/user/user/post.php
2005          0x7D5           Unix path: /company/user/user/put.php
3373          0xD2D           Unix path: /urban-airship/channel/channel/post.php
3789          0xECD           Unix path: /urban-airship/named-user/named-user/post.php
3901          0xF3D           Unix path: /user/categories/categories/delete.php
4005          0xFA5           Unix path: /user/categories/categories/get.php
4109          0x100D          Unix path: /user/categories/categories/put.php
4309          0x10D5          Unix path: /user/favorites/favorites/delete.php
lh
źródło
0

Indeks Git to plik binarny (zazwyczaj przechowywany w .git/index) zawierający posortowaną listę nazw ścieżek, z których każda ma uprawnienia i SHA1 obiektu blob;

git ls-filesmoże pokazać zawartość indeksu. Zwróć uwagę, że słowa index, stagei cachesą tym samym w Git: są używane zamiennie.

wprowadź opis obrazu tutaj

Indeks Git lub pamięć podręczna Git ma 3 ważne właściwości:

  1. Indeks zawiera wszystkie informacje niezbędne do wygenerowania pojedynczego (jednoznacznie określonego) obiektu drzewa.
  2. Indeks umożliwia szybkie porównania między definiowanym przez siebie obiektem drzewa a drzewem roboczym.
  3. Może efektywnie przedstawiać informacje o konfliktach scalania między różnymi obiektami drzewa, umożliwiając powiązanie każdej ścieżki z wystarczającymi informacjami o zaangażowanych drzewach, aby można było utworzyć trójstronne scalenie między nimi.

Źródło :

  1. https://mincong.io/2018/04/28/git-index/
  2. https://medium.com/hackernoon/understanding-git-index-4821a0765cf
Saikat
źródło