Cosa contiene ESATTAMENTE l'indice git?


178

Cosa contiene esattamente l'indice Git e quale comando posso usare per visualizzare il contenuto dell'indice?


Aggiornare

Grazie per tutte le tue risposte So che l'indice funge da area di gestione temporanea e ciò che è impegnato è nell'indice anziché nell'albero di lavoro. Sono solo curioso di sapere in cosa consiste un oggetto indice. Immagino che potrebbe essere un elenco di nome file / directory, coppie SHA-1, forse una specie di albero virtuale?

Esiste, nella terminologia di Git, qualche comando idraulico che posso usare per elencare il contenuto dell'indice?



3
dovresti leggere e guardare i diagrammi - molto utile: gitguys.com/topics/whats-the-deal-with-the-git-index
kernix

1
@kernix il dominio è scaduto. Non molto più utile.
Narendra-Choudhary,

Risposte:


162

Il libro Git contiene un articolo su ciò che include un indice :

L'indice è un file binario (generalmente conservato .git/index) contenente un elenco ordinato di nomi di percorso, ciascuno con autorizzazioni e SHA1 di un oggetto BLOB; git ls-filespuò mostrarti il ​​contenuto dell'indice:

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

Il problema Racy git fornisce alcuni dettagli in più su quella struttura:

L'indice è una delle strutture di dati più importanti in git.
Rappresenta uno stato dell'albero di lavoro virtuale registrando l'elenco dei percorsi e i relativi nomi di oggetto e funge da area di gestione temporanea per scrivere l'oggetto albero successivo da sottoporre a commit.
Lo stato è "virtuale", nel senso che non deve necessariamente e spesso non corrisponde ai file nell'albero di lavoro.


Per vedere di più, cfr. " git / git / Documentation / technical / index-format.txt ":

Il file di indice Git ha il seguente formato

Tutti i numeri binari sono in ordine di byte di rete.
La versione 2 è descritta qui se non diversamente specificato.

  • Un'intestazione di 12 byte composta da:
    • Firma a 4 byte :
      la firma è {' D', ' I', ' R', ' C'} (sta per " dircache")
    • Numero di versione a 4 byte :
      le versioni attualmente supportate sono 2, 3 e 4.
    • Numero a 32 bit di voci di indice.
  • Un numero di voci di indice ordinate .
  • Estensioni : le
    estensioni sono identificate dalla firma.
    Le estensioni opzionali possono essere ignorate se Git non le comprende.
    Git attualmente supporta l'albero nella cache e risolve le estensioni di annullamento.
    • Firma dell'estensione a 4 byte. Se il primo byte è ' A' .. 'Z ' l'estensione è facoltativa e può essere ignorata.
    • Dimensione a 32 bit dell'estensione
    • Dati di estensione
  • 160-bit SHA-1 sul contenuto del file indice prima di questo checksum.

commenti mljrg :

Se l'indice è il luogo in cui viene preparato il prossimo commit, perché " git ls-files -s" non restituisce nulla dopo il commit?

Perché l'indice rappresenta ciò che viene monitorato e subito dopo un commit, ciò che viene monitorato è identico all'ultimo commit ( git diff --cachednon restituisce nulla).

Così git ls-files -s elenca tutti i file tracciati (nome oggetto, bit modalità e numero fase nell'output).

Tale elenco (dell'elemento tracciato) viene inizializzato con il contenuto di un commit.
Quando si cambia ramo, il contenuto dell'indice viene ripristinato al commit a cui fa riferimento il ramo a cui si è appena passati.


Git 2.20 (Q4 2018) aggiunge una tabella di offset degli indici (IEOT) :

Vedi commit 77ff112 , commit 3255089 , commit abb4bb8 , commit c780b9c , commit 3b1d9e0 , commit 371ed0d (10 ott 2018) di Ben Peart ( benpeart) .
Vedi commit 252d079 (26 set 2018) di Nguyễn Thái Ngọc Duy ( pclouds) .
(Unita da Junio ​​C Hamano - gitster- in commit e27bfaa , 19 ott 2018)

ieot: aggiungi l'estensione IEOT (Index Entry Offset Table)

Questa patch consente di affrontare il costo della CPU per il caricamento dell'indice aggiungendo ulteriori dati all'indice che ci consentiranno di eseguire il multithreading efficiente del caricamento e della conversione delle voci della cache.

Ciò si ottiene aggiungendo un'estensione indice (facoltativa) che è una tabella di offset ai blocchi di voci della cache nel file indice.

Per farlo funzionare per gli indici V4, durante la scrittura delle voci della cache, "reimposta" periodicamente la compressione del prefisso codificando la voce corrente come se il nome del percorso per la voce precedente fosse completamente diverso e salvasse l'offset di quella voce nell'IEOT .
Fondamentalmente, con gli indici V4, genera offset in blocchi di voci compresse con prefisso.

Con la nuova impostazione di configurazione index.threads , il caricamento dell'indice è ora più veloce.


Di conseguenza ( utilizzando IEOT ), esegui il commit di 7bd9631 per ripulire la read-cache.c load_cache_entries_threaded()funzione per Git 2.23 (3 ° trimestre 2019).

Vedere commettere 8373037 , commettere d713e88 , commettere d92349d , commettere 113c29a , commettere c95fc72 , commettere 7a2a721 , commettere c016579 , commettere be27fb7 , commettere 13a1781 , commettere 7bd9631 , commettere 3c1dce8 , commettere cf7a901 , commettere d64db5b , commettere 76a7bc0 (9 maggio 2019) da Jeff King ( peff) .
(Unito da Junio ​​C Hamano - gitster- in commit c0e78f7 , 13 giu 2019)

read-cache: elimina il parametro inutilizzato dal caricamento thread

La load_cache_entries_threaded()funzione accetta un src_offsetparametro che non utilizza. Questo è stato lì sin dal suo inizio in 77ff112 ( read-cache: carica voci della cache sui thread di lavoro, 10-10-2018, Git v2.20.0-rc0).

Scavando sulla mailing list, quel parametro faceva parte di una precedente iterazione della serie , ma divenne inutile quando il codice passò all'uso dell'estensione IEOT.


6
Circa l'importanza se l'indice nel modello Git, vedi stackoverflow.com/questions/1450348/...
VonC

Il primo link qui sopra punta a una versione di git-scm che non ha un articolo sull'indice. Penso che l'intenzione fosse quella di puntare qui: schacon.github.io/gitbook/7_the_git_index.html
Kris Giesing

1
@KrisGiesing Grazie per il link. Ho aggiornato la risposta.
VonC

@VonC Se l'indice è il luogo in cui viene preparato il prossimo commit, perché "git ls-files -s" non restituisce nulla dopo il commit? Ci deve essere qualcosa di più sull'indice di quello che hai inserito nella tua risposta.
mljrg,

@mljrg non sono sicuro di seguirti: dopo un commit, lo stage (dove era in preparazione il commit) sarebbe vuoto, dato che il commit è stato fatto, non sarebbe?
VonC,

62

Analisi bit per bit

Ho deciso di fare un piccolo test per capire meglio il formato e ricercare alcuni campi in modo più dettagliato.

I seguenti risultati sono gli stessi per le versioni Git 1.8.5.2e 2.3.

Ho segnato dei punti che non sono sicuro / con cui non ho trovato TODO: sentiti libero di completare questi punti.

Come altri hanno già detto, l'indice è archiviato .git/index, non come un oggetto albero standard, e il suo formato è binario e documentato su: https://github.com/git/git/blob/master/Documentation/technical/index-format. testo

Le principali strutture che definiscono l'indice sono in cache.h , poiché l'indice è una cache per la creazione di commit.

Impostare

Quando iniziamo un repository di test con:

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

La .gitdirectory è simile a:

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

E se otteniamo il contenuto dell'unico oggetto:

git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85

Abbiamo capito a. Questo indica che:

  • i indexpunti per il contenuto del file, dal momento che git add bha creato un oggetto blob
  • memorizza i metadati nel file indice, non in un oggetto ad albero, poiché c'era un solo oggetto: il BLOB (sui normali oggetti Git, i metadati del BLOB sono memorizzati sull'albero)

analisi hd

Ora diamo un'occhiata all'indice stesso:

hd .git/index

dà:

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

Quindi concluderemo:

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

Prima arriva l'intestazione, definita in: struct cache_header :

  • 44 49 52 43: DIRC. TODO: perché è necessario?

  • 00 00 00 02: versione formato: 2. Il formato dell'indice si è evoluto nel tempo. Attualmente esiste una versione fino alla 4. Il formato dell'indice non dovrebbe costituire un problema quando si collabora tra computer diversi su GitHub perché i repository non archiviati non memorizzano l'indice: viene generato al momento del clone.

  • 00 00 00 01: conteggio dei file sull'indice: solo uno b,.

Successivamente inizia un elenco di voci di indice, definite da struct cache_entry Qui ne abbiamo solo una. Contiene:

  • un mucchio di metadati di file: 8 byte ctime, 8 byte mtime, quindi 4 byte: dispositivo, inode, modalità, UID e GID.

    Nota come:

    • ctimee mtimesono uguali (54 09 76 e6 1d 81 6f c6 ) previsti dal momento che non abbiamo modificato il file

      I primi byte sono secondi dall'EPOCH in esadecimale:

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

      dà:

      Fri Sep  5 10:40:06 CEST 2014
      

      Questo è quando ho fatto questo esempio.

      I secondi 4 byte sono nanosecondi.

    • UID e GID sono 00 00 03 e8, 1000 in esadecimale: un valore comune per le configurazioni a utente singolo.

    Tutti questi metadati, molti dei quali non sono presenti negli oggetti ad albero, consentono a Git di verificare se un file è stato modificato rapidamente senza confrontare l'intero contenuto.

  • all'inizio della riga 30:: 00 00 00 02dimensione del file: 2 byte ( ae \nda echo)

  • 78 98 19 22 ... c1 99 4e 85: 20 byte SHA-1 rispetto al contenuto precedente della voce. Si noti che, secondo i miei esperimenti con l'assunzione di un flag valido , i flag che lo seguono non sono considerati in questo SHA-1.

  • Flag di 2 byte: 00 01

    • 1 bit: assume flag valido. Le mie indagini indicano che questa bandiera mal nominata è dovegit update-index --assume-unchanged memorizza il suo stato: https://stackoverflow.com/a/28657085/895245

    • Flag esteso a 1 bit. Determina se i flag estesi sono presenti o meno. Deve essere0 sulla versione 2 che non ha flag estesi.

    • Flag di fase a 2 bit utilizzato durante l'unione. Le fasi sono documentate inman git-merge :

      • 0: file normale, non in conflitto di unione
      • 1: base
      • 2: nostro
      • 3: il loro

      Durante un conflitto di unione, tutte le fasi da 1-3 sono memorizzate nell'indice per consentire operazioni simili git checkout --ours .

      Se sì git add, viene aggiunto uno stadio 0 all'indice per il percorso e Git saprà che il conflitto è stato contrassegnato come risolto. TODO: controlla questo.

    • 12 bit di lunghezza del percorso che seguirà 0 01:: 1 byte solo da quando il percorso erab

  • Flag estesi a 2 byte. Significativo solo se la "bandiera estesa" era impostata sulle bandiere di base. FARE.

  • 62(ASCII b): percorso a lunghezza variabile. Lunghezza determinato nelle bandiere precedenti, qui solo 1 byte, b.

Quindi arriva un 00: 1-8 byte di zero padding in modo che il percorso venga terminato con null e l'indice terminerà con un multiplo di 8 byte. Questo succede solo prima dell'indice versione 4.

Non sono state utilizzate estensioni. Git lo sa perché non ci sarebbe abbastanza spazio nel file per il checksum.

Infine c'è un checksum di 20 byte ee 33 c0 3a .. 09 ab 49 94sul contenuto dell'indice.


1
Molto interessante. +1. Ciò illustra bene la mia risposta . Mi chiedo se quei risultati potrebbero cambiare con l'ultimo Git 2.1+.
VonC,

3
@NielsBom sì, funzionerebbe anche. Quando interpreto i programmi, preferisco adottare due approcci: il primo empirico per vedere quali output genera e solo dopo leggere la fonte. Altrimenti si potrebbe rimanere coinvolti in casi limite del codice sorgente che non compaiono nemmeno su output semplici. Certo, ho guardato le strutture sorgente per aiutarmi a guidarmi, e ogni TODO può risolvere la mia lettura di come vengono manipolate quelle strutture, che è la parte difficile.
Ciro Santilli 14 冠状 病 六四 事件 法轮功

1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: Se modifico l'indice in un editor esadecimale e aggiorno il suo checksum a 20 byte, c'è un comando per aggiornare lo sha1 che è memorizzato in altri oggetti? (git si lamenta che la firma dell'indice sha1 sia corrotta) . Inoltre, i dati dell'indice vengono archiviati in un modo completamente diverso quando vengono inviati su richieste push.
user2284570

1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: scopi di sicurezza. Sto solo cercando il ben noto tipo di attacchi di file di immagini raster applicati a database / oggetti git. (ovviamente so che la maggior parte dell'implementazione si è recentemente occupata di quella prospettiva, ma probabilmente non tutte)  Quindi sto cercando soprattutto strutture di dati binari che descrivano la lunghezza di un array. (per quanto riguarda i buffer di testo sembra che la terminazione nulla sia la norma per indicare il numero di righe)
user2284570

1
Per quanto riguarda il git addtuo TODO: hai ragione. Se si dispone di voci di indice high-stage (un conflitto) in un determinato percorso, quando si è git addquel percorso, tutte le voci di indice high-stage verranno rimosse e la copia della directory di lavoro verrà aggiunta in fase 0. (Risoluzione del conflitto).
Edward Thomson,

11

L'indice Git è un'area di gestione temporanea tra la directory di lavoro e il repository. Puoi utilizzare l'indice per creare una serie di modifiche che desideri impegnare insieme. Quando si crea un commit, ciò che è commit è ciò che è attualmente in questo indice, non quello che si trova nella directory di lavoro.

Per vedere cosa c'è dentro l'indice, emetti il ​​comando:

git status

Quando esegui git status, puoi vedere quali file sono messi in scena (attualmente nel tuo indice), quali sono modificati ma non ancora messi in scena e quali sono completamente non tracciati.

Puoi leggere questo . Una ricerca su Google genera molti collegamenti, che dovrebbero essere abbastanza autosufficienti.


7
git statusnon elenca tutti i file dall'indice. Elenca solo i file che differiscono tra indice e directory di lavoro. Per vedere tutti i file nell'indice, è necessario utilizzare git ls-files.
Akash Agrawal,

1
@AkashAgrawal, git status lo fa nel file di indice di elenco fatto, indipendentemente dal fatto che si differenziano tra indice e workdir.
Acumenus,

3
sì, elenca ALCUNI dei file di indice, ma non mostra tutto ciò che è all'interno dell'indice, che è ciò che dice la sua affermazione nella sua risposta. È come dire che ci sono 2 palline verdi e 3 palline rosse all'interno di una scatola. Per vedere cosa c'è dentro la scatola, estrarre le 2 palline verdi. Quello che Akash ha detto è più preciso, per vedere tutti i file nell'indice, usa git ls-files.
dave4jr,

3
Infatti. git statuselenca i file che si trovano nell'indice, sì, ma non elenca tutti i file nell'indice. Spiegare come funziona git status effettivamente sarebbe una risposta utile ad alcune domande, anche se probabilmente non questa.
Edward Thomson,

1
git statusmostra lo stato dell'albero di lavoro (differenza tra l'albero di lavoro e l'indice). In realtà non mostra l'indice. git-scm.com/docs/git-status
wisbucky,

1

Ecco cosa ti serviva esattamente, usa questo comando.

$ 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

Git index è un file binario (generalmente conservato .git/index) contenente un elenco ordinato di nomi di percorso, ciascuno con autorizzazioni e SHA1 di un oggetto BLOB;

git ls-filespuò mostrarti il ​​contenuto dell'indice. Nota che le parole index, stagee cachesono la stessa cosa in Git: sono usate in modo intercambiabile.

inserisci qui la descrizione dell'immagine

Git index, o Git cache, ha 3 proprietà importanti:

  1. L'indice contiene tutte le informazioni necessarie per generare un singolo oggetto ad albero (determinato in modo univoco).
  2. L'indice consente confronti rapidi tra l'oggetto albero che definisce e l'albero di lavoro.
  3. Può rappresentare in modo efficiente informazioni sui conflitti di unione tra diversi oggetti dell'albero, consentendo a ciascun nome di percorso di essere associato a informazioni sufficienti sugli alberi coinvolti che è possibile creare una fusione a tre vie tra loro.

Fonte :

  1. https://mincong.io/2018/04/28/git-index/
  2. https://medium.com/hackernoon/understanding-git-index-4821a0765cf
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.