Was enthält der Git-Index genau?


176

Was enthält der Git-Index genau und mit welchem ​​Befehl kann ich den Inhalt des Index anzeigen?


Aktualisieren

Vielen Dank für alle Ihre Antworten. Ich weiß, dass der Index als Staging-Bereich fungiert, und was festgeschrieben wird, befindet sich im Index und nicht im Arbeitsbaum. Ich bin nur neugierig, woraus ein Indexobjekt besteht. Ich denke, es könnte eine Liste von Dateinamen / Verzeichnisnamen, SHA-1-Paaren, vielleicht eine Art virtueller Baum sein?

Gibt es in der Git-Terminologie einen Installationsbefehl , mit dem ich den Inhalt des Index auflisten kann?



3
Sie sollten Diagramme lesen und ansehen - sehr hilfreich: gitguys.com/topics/whats-the-deal-with-the-git-index
kernix

1
@kernix die Domain ist abgelaufen. Nicht mehr sehr hilfreich.
Narendra-Choudhary

Antworten:


161

Das Git-Buch enthält einen Artikel darüber, was ein Index enthält :

Der Index ist eine Binärdatei (im Allgemeinen gespeichert .git/index), die eine sortierte Liste von Pfadnamen mit jeweils Berechtigungen und dem SHA1 eines Blob-Objekts enthält. git ls-fileskann Ihnen den Inhalt des Index zeigen:

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

Das Racy-Git-Problem enthält einige weitere Details zu dieser Struktur:

Der Index ist eine der wichtigsten Datenstrukturen in Git.
Es stellt einen virtuellen Arbeitsbaumstatus dar, indem eine Liste von Pfaden und deren Objektnamen aufgezeichnet wird, und dient als Bereitstellungsbereich zum Ausschreiben des nächsten festzuschreibenden Baumobjekts.
Der Status ist "virtuell" in dem Sinne, dass er nicht unbedingt mit den Dateien im Arbeitsbaum übereinstimmen muss und häufig nicht übereinstimmt.


Um mehr zu sehen, vgl. " git / git / Documentation / technisch / index-format.txt ":

Die Git-Indexdatei hat das folgende Format

Alle Binärzahlen sind in Netzwerkbyte-Reihenfolge.
Version 2 wird hier beschrieben, sofern nicht anders angegeben.

  • Ein 12-Byte-Header bestehend aus:
    • 4-Byte- Signatur :
      Die Signatur lautet {' D', ' I', ' R', ' C'} (steht für " dircache")
    • 4-Byte- Versionsnummer :
      Die derzeit unterstützten Versionen sind 2, 3 und 4.
    • 32-Bit-Anzahl von Indexeinträgen.
  • Eine Reihe von sortierten Indexeinträgen .
  • Erweiterungen :
    Erweiterungen werden durch Signatur identifiziert.
    Optionale Erweiterungen können ignoriert werden, wenn Git sie nicht versteht.
    Git unterstützt derzeit zwischengespeicherten Baum und löst Rückgängig-Erweiterungen auf.
    • 4-Byte-Erweiterungssignatur. Wenn das erste Byte ' A' .. ' Z' ist, ist die Erweiterung optional und kann ignoriert werden.
    • 32-Bit-Größe der Erweiterung
    • Erweiterungsdaten
  • 160-Bit-SHA-1 über den Inhalt der Indexdatei vor dieser Prüfsumme.

mljrg Kommentare :

Wenn der Index der Ort ist, an dem das nächste Commit vorbereitet wird, warum gibt " git ls-files -s" nach dem Commit nichts zurück?

Da der Index darstellt, was verfolgt wird , und direkt nach einem Commit, ist das, was verfolgt wird, identisch mit dem letzten Commit ( git diff --cachedgibt nichts zurück).

So git ls-files -slistet alle Dateien aufgespürt (Objektnamen, Modusbits und Stufenzahl in der Ausgabe).

Diese Liste (des verfolgten Elements) wird mit dem Inhalt eines Commits initialisiert.
Wenn Sie den Zweig wechseln, wird der Indexinhalt auf das Commit zurückgesetzt, auf das der Zweig verweist, zu dem Sie gerade gewechselt haben.


Git 2.20 (Q4 2018) fügt eine Indexeintrags-Offset-Tabelle (IEOT) hinzu :

Siehe Commit 77ff112 , Commit 3255089 , Commit abb4bb8 , Commit c780b9c , Commit 3b1d9e0 , Commit 371ed0d (10. Oktober 2018) von Ben Peart ( benpeart) .
Siehe Commit 252d079 (26. September 2018) von Nguyễn Thái Ngọc Duy ( pclouds) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit e27bfaa , 19. Oktober 2018)

ieot: IEOT-Erweiterung (Index Entry Offset Table) hinzufügen

Mit diesem Patch können Sie die CPU-Kosten für das Laden des Index beheben, indem Sie dem Index zusätzliche Daten hinzufügen, mit denen wir das Laden und Konvertieren von Cache-Einträgen effizient multithreading können.

Dies wird erreicht, indem eine (optionale) Indexerweiterung hinzugefügt wird, die eine Tabelle mit Offsets zu Blöcken von Cache-Einträgen in der Indexdatei ist.

Damit dies für V4-Indizes funktioniert, wird beim Schreiben der Cache-Einträge die Präfixkomprimierung regelmäßig "zurückgesetzt", indem der aktuelle Eintrag so codiert wird, als ob der Pfadname für den vorherigen Eintrag völlig anders wäre, und der Offset dieses Eintrags im IEOT gespeichert wird .
Grundsätzlich werden bei V4-Indizes Offsets in Blöcken von vorfixkomprimierten Einträgen generiert.

Mit der neuen Konfigurationseinstellung index.threads ist das Laden des Index jetzt schneller.


Als Ergebnis ( bei Verwendung von IEOT ) bereinigen Sie 7bd9631 die read-cache.c load_cache_entries_threaded()Funktion für Git 2.23 (Q3 2019).

Sehen Sie verpflichten 8373037 , begehen d713e88 , begehen d92349d , begehen 113c29a , begehen c95fc72 , begehen 7a2a721 , begehen c016579 , begehen be27fb7 , begehen 13a1781 , begehen 7bd9631 , begehen 3c1dce8 , begehen cf7a901 , begehen d64db5b , begehen 76a7bc0 (9. Mai 2019) von Jeff King ( peff) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit c0e78f7 , 13. Juni 2019)

Lese-Cache: Nicht verwendete Parameter aus der Thread-Last löschen

Die load_cache_entries_threaded()Funktion verwendet einen src_offsetParameter, den sie nicht verwendet. Dies ist seit seiner Einführung in 77ff112 vorhanden ( read-cache: Laden von Cache-Einträgen in Worker-Threads, 2018-10-10, Git v2.20.0-rc0).

Dieser Parameter war Teil einer früheren Iteration der Serie , wurde jedoch unnötig, als der Code auf die Verwendung der IEOT-Erweiterung umgestellt wurde.



Der erste Link oben verweist auf eine Version von git-scm, die keinen Artikel im Index enthält. Ich denke, die Absicht war, hier zu zeigen: schacon.github.io/gitbook/7_the_git_index.html
Kris Giesing

1
@KrisGiesing Danke für den Link. Ich habe die Antwort aktualisiert.
VonC

@VonC Wenn der Index der Ort ist, an dem das nächste Commit vorbereitet wird, warum gibt "git ls-files -s" nach dem Commit nichts zurück? Der Index muss etwas mehr enthalten, als Sie in Ihre Antwort eingegeben haben.
mljrg

@mljrg Ich bin mir nicht sicher, ob ich Ihnen folge: Nach einem Commit wäre die Phase (in der das Commit vorbereitet wurde) leer, da das Commit abgeschlossen wurde, nicht wahr?
VonC

62

Stück für Stück Analyse

Ich habe beschlossen, ein wenig zu testen, um das Format besser zu verstehen und einige Bereiche genauer zu untersuchen.

Die folgenden Ergebnisse sind für Git-Versionen 1.8.5.2und gleich 2.3.

Ich habe Punkte markiert, bei denen ich mir nicht sicher bin / die ich nicht gefunden habe TODO: Bitte ergänzen Sie diese Punkte.

Wie bereits erwähnt, wird der Index unter .git/indexund nicht als Standardbaumobjekt gespeichert. Sein Format ist binär und dokumentiert unter: https://github.com/git/git/blob/master/Documentation/technical/index-format. TXT

Die Hauptstrukturen, die den Index definieren, befinden sich in cache.h , da der Index ein Cache zum Erstellen von Commits ist.

Konfiguration

Wenn wir ein Test-Repository starten mit:

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

Das .gitVerzeichnis sieht folgendermaßen aus:

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

Und wenn wir den Inhalt des einzigen Objekts erhalten:

git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85

Wir bekommen a. Dies zeigt an, dass:

  • die indexverweist auf den Dateiinhalt, da git add bein Blob-Objekt erstellt wurde
  • Es speichert die Metadaten in der Indexdatei und nicht in einem Baumobjekt, da es nur ein einziges Objekt gab: den Blob (bei normalen Git-Objekten werden Blob-Metadaten im Baum gespeichert)

HD-Analyse

Schauen wir uns nun den Index selbst an:

hd .git/index

Gibt:

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

Als nächstes werden wir schließen:

  | 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
  | ...                                                       |

Zuerst kommt der Header, definiert unter: struct cache_header :

  • 44 49 52 43: DIRC. TODO: Warum ist das notwendig?

  • 00 00 00 02: format version: 2. Das Indexformat hat sich im Laufe der Zeit weiterentwickelt. Derzeit gibt es eine Version bis 4. Das Format des Index sollte bei der Zusammenarbeit zwischen verschiedenen Computern auf GitHub kein Problem darstellen, da nackte Repositorys den Index nicht speichern: Er wird zum Zeitpunkt des Klonens generiert.

  • 00 00 00 01: Anzahl der Dateien im Index: nur eine , b.

Als nächstes beginnt eine Liste von Indexeinträgen , die durch struct cache_entry definiert sind. Hier haben wir nur einen. Es beinhaltet:

  • Eine Reihe von Dateimetadaten: 8 Byte ctime, 8 Byte mtime, dann 4 Byte: Gerät, Inode, Modus, UID und GID.

    Beachten Sie, wie:

    • ctimeund mtimesind die gleichen ( 54 09 76 e6 1d 81 6f c6) wie erwartet, da wir die Datei nicht geändert haben

      Die ersten Bytes sind Sekunden seit EPOCH in hex:

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

      Gibt:

      Fri Sep  5 10:40:06 CEST 2014
      

      Zu diesem Zeitpunkt habe ich dieses Beispiel gemacht.

      Die zweiten 4 Bytes sind Nanosekunden.

    • UID und GID sind 00 00 03 e81000 in hex: ein allgemeiner Wert für Einzelbenutzer-Setups.

    Mit all diesen Metadaten, von denen die meisten nicht in Baumobjekten vorhanden sind, kann Git überprüfen, ob sich eine Datei schnell geändert hat, ohne den gesamten Inhalt zu vergleichen.

  • am Anfang der Zeile 30: 00 00 00 02: Dateigröße: 2 Bytes ( aund \nvon echo)

  • 78 98 19 22 ... c1 99 4e 85: 20 Byte SHA-1 über dem vorherigen Inhalt des Eintrags. Beachten Sie, dass gemäß meinen Experimenten mit dem angenommenen gültigen Flag die darauf folgenden Flags in diesem SHA-1 nicht berücksichtigt werden.

  • 2-Byte-Flags: 00 01

    • 1 Bit: Gültiges Flag annehmen. Meine Untersuchungen zeigen, dass in dieser schlecht benannten Flagge git update-index --assume-unchangedder Status gespeichert ist : https://stackoverflow.com/a/28657085/895245

    • 1 Bit erweitertes Flag. Legt fest, ob die erweiterten Flags vorhanden sind oder nicht. Muss 0auf Version 2 sein, die keine erweiterten Flags hat.

    • 2-Bit-Stufenflag, das beim Zusammenführen verwendet wird. Etappen sind dokumentiert in man git-merge:

      • 0: reguläre Datei, nicht in einem Zusammenführungskonflikt
      • 1: Basis
      • 2: unsere
      • 3: ihre

      Während eines Zusammenführungskonflikts werden alle Phasen von 1 bis 3 im Index gespeichert, um Operationen wie z git checkout --ours.

      Wenn Sie git add, wird dem Index für den Pfad eine Stufe 0 hinzugefügt, und Git weiß, dass der Konflikt als gelöst markiert wurde. TODO: Überprüfen Sie dies.

    • 12-Bit-Länge des folgenden Pfads :: 0 011 Byte nur seit dem Pfadb

  • 2 Byte erweiterte Flags. Nur sinnvoll, wenn das "erweiterte Flag" für die Basisflags gesetzt wurde. MACHEN.

  • 62(ASCII b): Pfad variabler Länge. Länge in den vorherigen Flags bestimmt, hier nur 1 Byte , b.

Dann kommt ein 00: 1-8 Bytes mit Null-Auffüllung, so dass der Pfad nullterminiert wird und der Index mit einem Vielfachen von 8 Bytes endet. Dies geschieht nur vor der Indexversion 4.

Es wurden keine Erweiterungen verwendet. Git weiß das, weil in der Datei nicht mehr genügend Platz für die Prüfsumme vorhanden ist.

Schließlich gibt es eine 20-Byte-Prüfsumme ee 33 c0 3a .. 09 ab 49 94über den Inhalt des Index.


1
Sehr interessant. +1. Das zeigt meine eigene Antwort sehr gut. Ich frage mich, ob sich diese Ergebnisse mit dem neuesten Git 2.1+ ändern würden.
VonC

3
@NielsBom ja, das würde auch funktionieren. Bei der Interpretation von Programmen bevorzuge ich zwei Ansätze: erstens empirisch, um zu sehen, welche Ausgaben sie erzeugen, und erst dann die Quelle lesen. Andernfalls könnte man in Quellcode-Randfälle verwickelt werden, die nicht einmal auf einfachen Ausgaben erscheinen. Natürlich habe ich mir die Quellstrukturen angesehen, um mich zu führen, und jedes TODO kann gelöst werden, indem ich lese, wie diese Strukturen manipuliert werden, was der schwierige Teil ist.
Ciro Santilli 14 冠状 病 六四 事件 14

1
@CiroSantilli If 事件 法轮功 纳米比亚 纳米比亚 视: Wenn ich den Index in einem Hex-Editor ändere und seine 20-Byte-Prüfsumme aktualisiere, gibt es einen Befehl zum Aktualisieren des sha1, der in anderen Objekten gespeichert ist? (Git beschwert sich, dass die sha1-Signatur des Index beschädigt ist) . Außerdem werden die Indexdaten beim Senden über Push-Anforderungen auf völlig andere Weise gespeichert.
user2284570

1
@CiroSantilli Security 事件 法轮功 纳米比亚 纳米比亚 视: Sicherheitszwecke. Ich suche nur nach den bekannten Angriffen auf Rasterbilddateien, die auf Git-Datenbanken / Objekte angewendet werden. (Natürlich weiß ich, dass sich die meisten Implementierungen in letzter Zeit um diese Perspektive gekümmert haben, aber wahrscheinlich nicht alle).  Daher suche ich besonders nach binären Datenstrukturen, die die Länge eines Arrays angeben. (In Bezug auf
Textpuffer

1
In Bezug git addauf Ihre TODO: Sie sind richtig. Wenn Sie über einen bestimmten Pfad über hochrangige Indexeinträge (einen Konflikt) verfügen, werden bei git adddiesem Pfad alle übergeordneten Indexeinträge entfernt und die Arbeitsverzeichniskopie wird schrittweise hinzugefügt 0. (Lösung des Konflikts).
Edward Thomson

11

Der Git-Index ist ein Staging-Bereich zwischen Ihrem Arbeitsverzeichnis und Ihrem Repository. Mit dem Index können Sie eine Reihe von Änderungen erstellen, die Sie gemeinsam festschreiben möchten. Wenn Sie ein Commit erstellen, wird festgeschrieben, was sich derzeit in diesem Index befindet und nicht in Ihrem Arbeitsverzeichnis.

Geben Sie den folgenden Befehl ein, um zu sehen, was sich im Index befindet:

git status

Wenn Sie den Git-Status ausführen, können Sie sehen, welche Dateien (derzeit in Ihrem Index) bereitgestellt werden, welche geändert, aber noch nicht bereitgestellt wurden und welche vollständig nicht verfolgt werden.

Sie können lesen diese . Eine Google-Suche wirft viele Links auf, die ziemlich autark sein sollten.


7
git statuslistet nicht alle Dateien aus dem Index auf. Es werden nur die Dateien aufgelistet, die sich zwischen Index und Arbeitsverzeichnis unterscheiden. Um alle Dateien im Index anzuzeigen, müssen Sie verwenden git ls-files.
Akash Agrawal

1
@AkashAgrawal git status listet tatsächlich Indexdateien auf, unabhängig davon, ob sie sich zwischen Index und Arbeitsverzeichnis unterscheiden.
Acumenus

3
Ja, es listet EINIGE der Indexdateien auf, aber es zeigt Ihnen nicht alles, was sich im Index befindet, wie seine Aussage in seiner Antwort sagt. Das heißt, in einer Schachtel befinden sich 2 grüne und 3 rote Kugeln. Ziehen Sie die 2 grünen Kugeln heraus, um zu sehen, was sich in der Schachtel befindet. Was Akash sagte, ist am genauesten. Um alle Dateien im Index zu sehen, verwenden Sie git ls-files.
Dave4JR

3
Tatsächlich. git statuslistet Dateien auf, die sich im Index befinden, ja, listet jedoch nicht alle Dateien im Index auf. Zu erklären, wie es git status tatsächlich funktioniert, wäre eine nützliche Antwort auf eine Frage, wenn auch wahrscheinlich nicht auf diese.
Edward Thomson

1
git statusZeigt den Status des Arbeitsbaums an (Unterschied zwischen Arbeitsbaum und Index). Der Index wird nicht angezeigt. git-scm.com/docs/git-status
wisbucky

1

Hier ist, was Sie genau benötigt, verwenden Sie diesen Befehl.

$ 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

0

Der Git-Index ist eine Binärdatei (im Allgemeinen gespeichert .git/index), die eine sortierte Liste von Pfadnamen mit jeweils Berechtigungen und dem SHA1 eines Blob-Objekts enthält.

git ls-fileskann Ihnen den Inhalt des Index zeigen. Bitte beachten Sie, dass Worte index, stageund cachedasselbe ist in Git: sie werden austauschbar verwendet.

Geben Sie hier die Bildbeschreibung ein

Der Git-Index oder Git-Cache hat drei wichtige Eigenschaften:

  1. Der Index enthält alle Informationen, die zum Generieren eines einzelnen (eindeutig bestimmten) Baumobjekts erforderlich sind.
  2. Der Index ermöglicht schnelle Vergleiche zwischen dem von ihm definierten Baumobjekt und dem Arbeitsbaum.
  3. Es kann Informationen zu Zusammenführungskonflikten zwischen verschiedenen Baumobjekten effizient darstellen, sodass jedem Pfadnamen ausreichende Informationen zu den beteiligten Bäumen zugeordnet werden können, sodass Sie eine Drei-Wege-Zusammenführung zwischen ihnen erstellen können.

Quelle :

  1. https://mincong.io/2018/04/28/git-index/
  2. https://medium.com/hackernoon/understanding-git-index-4821a0765cf
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.