Que contient exactement l'index git?


178

Que contient exactement l'index Git et quelle commande puis-je utiliser pour afficher le contenu de l'index?


Mettre à jour

Merci pour toutes vos réponses. Je sais que l'index agit comme une zone de transit et que ce qui est validé se trouve dans l'index plutôt que dans l'arbre de travail. Je suis simplement curieux de savoir en quoi consiste un objet index. Je suppose que cela pourrait être une liste de nom de fichier / nom de répertoire, des paires SHA-1, une sorte d'arbre virtuel peut-être?

Existe-t-il, dans la terminologie Git, une commande de plomberie que je puisse utiliser pour lister le contenu de l'index?



3
vous devriez lire et regarder les diagrammes - très utiles: gitguys.com/topics/whats-the-deal-with-the-git-index
kernix

1
@kernix le domaine a expiré. Ce n'est plus très utile.
narendra-choudhary

Réponses:


162

Le livre Git contient un article sur ce qu'un index comprend :

L'index est un fichier binaire (généralement conservé .git/index) contenant une liste triée de noms de chemin, chacun avec des autorisations et le SHA1 d'un objet blob; git ls-filespeut vous montrer le contenu de l'index:

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

Le problème git Racy donne plus de détails sur cette structure:

L'index est l'une des structures de données les plus importantes de git.
Il représente un état d'arborescence de travail virtuel en enregistrant la liste des chemins et leurs noms d'objet et sert de zone de transit pour écrire le prochain objet d'arborescence à valider.
L'état est "virtuel" dans le sens où il ne doit pas nécessairement correspondre, et souvent pas, aux fichiers de l'arborescence de travail.


Pour en savoir plus, cf. " git / git / Documentation / technical / index-format.txt ":

Le fichier d'index Git a le format suivant

Tous les nombres binaires sont dans l'ordre des octets du réseau. Sauf indication contraire, la
version 2 est décrite ici.

  • Un en-tête de 12 octets composé de:
    • Signature à 4 octets :
      la signature est {' D', ' I', ' R', ' C'} (signifie " dircache")
    • Numéro de version sur 4 octets :
      les versions actuellement prises en charge sont 2, 3 et 4.
    • Nombre d'entrées d'index de 32 bits.
  • Un certain nombre d' entrées d'index triées .
  • Extensions : les
    extensions sont identifiées par signature.
    Les extensions facultatives peuvent être ignorées si Git ne les comprend pas.
    Git prend actuellement en charge l'arborescence mise en cache et résout les extensions d'annulation.
    • Signature d'extension de 4 octets. Si le premier octet est « A..» Z, l'extension est facultative et peut être ignorée.
    • Taille 32 bits de l'extension
    • Données d'extension
  • SHA-1 160 bits sur le contenu du fichier d'index avant cette somme de contrôle.

commentaires mljrg :

Si l'index est l'endroit où le prochain commit est préparé, pourquoi " git ls-files -s" ne retourne-t-il rien après le commit?

Comme l'index représente ce qui est suivi , et juste après une validation, ce qui est suivi est identique à la dernière validation ( git diff --cachedne renvoie rien).

Répertorie donc git ls-files -stous les fichiers suivis (nom de l'objet, bits de mode et numéro d'étape dans la sortie).

Cette liste (des éléments suivis) est initialisée avec le contenu d'un commit.
Lorsque vous changez de branche, le contenu de l'index est réinitialisé au commit référencé par la branche vers laquelle vous venez de basculer.


Git 2.20 (Q4 2018) ajoute une table de décalage d'entrée d'index (IEOT) :

Voir commit 77ff112 , commit 3255089 , commit abb4bb8 , commit c780b9c , commit 3b1d9e0 , commit 371ed0d (10 octobre 2018) par Ben Peart ( benpeart) .
Voir commit 252d079 (26 septembre 2018) par Nguyễn Thái Ngọc Duy ( pclouds) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit e27bfaa , 19 oct 2018)

ieot: ajout de l'extension IEOT (Index Entry Offset Table)

Ce correctif permet de traiter le coût CPU du chargement de l'index en ajoutant des données supplémentaires à l'index qui nous permettront de multi-thread efficacement le chargement et la conversion des entrées de cache.

Il accomplit cela en ajoutant une extension d'index (facultative) qui est une table de décalages aux blocs d'entrées de cache dans le fichier d'index.

Pour que cela fonctionne pour les index V4, lors de l'écriture des entrées de cache, il "réinitialise" périodiquement la compression de préfixe en codant l'entrée actuelle comme si le nom de chemin de l'entrée précédente était complètement différent et enregistre le décalage de cette entrée dans l'IEOT .
Fondamentalement, avec les index V4, il génère des décalages en blocs d'entrées compressées par préfixe.

Avec le nouveau paramètre de configuration index.threads , le chargement de l'index est désormais plus rapide.


En conséquence ( de l'utilisation d'IEOT ), validez 7bd9631 pour nettoyer la read-cache.c load_cache_entries_threaded()fonction pour Git 2.23 (Q3 2019).

Voir le commit 8373037 , le commit d713e88 , le commit d92349d , le commit 113c29a , le commit c95fc72 , le commit 7a2a721 , le commit c016579 , le commit be27fb7 , le commit 13a1781 , le commit 7bd9631 , le commit 3c1dce8 , le commit cf7a901 , le commit d64db5b , le commit de Jeff Kingpeff (09 mai 2019) ( ) .
(Fusionné par Junio ​​C Hamano - gitster- in commit c0e78f7 , 13 juin 2019)

read-cache: supprime le paramètre inutilisé de la charge threadée

La load_cache_entries_threaded()fonction prend un src_offsetparamètre qu'elle n'utilise pas. Cela existe depuis sa création dans 77ff112 ( read-cache: charger les entrées de cache sur les threads de travail, 10/10/2018, Git v2.20.0-rc0).

En creusant dans la liste de diffusion, ce paramètre faisait partie d'une itération antérieure de la série , mais est devenu inutile lorsque le code est passé à l'utilisation de l'extension IEOT.


6
À propos de l'importance de l'index dans le modèle Git, voir stackoverflow.com/questions/1450348
...

Le premier lien ci-dessus pointe vers une version de git-scm qui n'a pas d'article sur l'index. Je pense que l'intention était de pointer ici: schacon.github.io/gitbook/7_the_git_index.html
Kris Giesing

1
@KrisGiesing Merci pour le lien. J'ai mis à jour la réponse.
VonC

@VonC Si l'index est l'endroit où le prochain commit est préparé, pourquoi "git ls-files -s" ne renvoie rien après le commit? Il doit y avoir quelque chose de plus dans l'index que ce que vous avez mis dans votre réponse.
mljrg

@mljrg pas sûr que je vous suive: après un commit, l'étape (où le commit était en cours de préparation) serait vide, puisque le commit a été fait, n'est-ce pas?
VonC

62

Analyse bit par bit

J'ai décidé de faire un petit test pour mieux comprendre le format et rechercher certains des domaines plus en détail.

Les résultats ci-dessous sont les mêmes pour les versions Git 1.8.5.2et 2.3.

J'ai marqué des points avec lesquels je ne suis pas sûr / que je n'ai pas trouvé TODO: n'hésitez pas à compléter ces points.

Comme d'autres l'ont mentionné, l'index est stocké sous .git/index, et non comme un objet d'arborescence standard, et son format est binaire et documenté à l' adresse : https://github.com/git/git/blob/master/Documentation/technical/index-format. SMS

Les principales structures qui définissent l'index se trouvent dans cache.h , car l'index est un cache pour créer des validations.

Installer

Lorsque nous démarrons un référentiel de test avec:

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

Le .gitrépertoire ressemble à:

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

Et si nous obtenons le contenu du seul objet:

git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85

Nous obtenons a. Cela indique que:

  • les indexpoints vers le contenu du fichier, depuis la git add bcréation d'un objet blob
  • il stocke les métadonnées dans le fichier d'index, pas dans un objet d'arborescence, car il n'y avait qu'un seul objet: le blob (sur les objets Git normaux, les métadonnées de blob sont stockées dans l'arborescence)

analyse HD

Regardons maintenant l'index lui-même:

hd .git/index

Donne:

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

Ensuite, nous conclurons:

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

Vient d'abord l'en-tête, défini à: struct cache_header :

  • 44 49 52 43: DIRC. TODO: pourquoi est-ce nécessaire?

  • 00 00 00 02: format version: 2. Le format de l'index a évolué avec le temps. Il existe actuellement une version jusqu'à 4. Le format de l'index ne devrait pas être un problème lors de la collaboration entre différents ordinateurs sur GitHub car les dépôts nus ne stockent pas l'index: il est généré au moment du clonage.

  • 00 00 00 01: Nombre de fichiers sur l'index: un seul, b.

Ensuite commence une liste d'entrées d'index, définies par struct cache_entry. Ici, nous n'en avons qu'une. Il contient:

  • un tas de métadonnées de fichier: 8 octets ctime, 8 octets mtime, puis 4 octets: périphérique, inode, mode, UID et GID.

    Notez comment:

    • ctimeet mtimesont les mêmes ( 54 09 76 e6 1d 81 6f c6) que prévu puisque nous n'avons pas modifié le fichier

      Les premiers octets sont des secondes depuis EPOCH en hexadécimal:

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

      Donne:

      Fri Sep  5 10:40:06 CEST 2014
      

      C'est alors que j'ai fait cet exemple.

      Les 4 octets suivants sont des nanosecondes.

    • UID et GID sont 00 00 03 e8, 1000 en hexadécimal: une valeur commune pour les configurations mono-utilisateur.

    Toutes ces métadonnées, dont la plupart ne sont pas présentes dans les objets d'arborescence, permettent à Git de vérifier si un fichier a changé rapidement sans comparer le contenu entier.

  • en début de ligne 30:: 00 00 00 02taille du fichier: 2 octets ( aet \nde echo)

  • 78 98 19 22 ... c1 99 4e 85: 20 octets SHA-1 sur le contenu précédent de l'entrée. Notez que selon mes expériences avec l'indicateur supposer valide , les indicateurs qui le suivent ne sont pas pris en compte dans ce SHA-1.

  • Indicateurs 2 octets: 00 01

    • 1 bit: suppose un drapeau valide. Mes investigations indiquent que ce drapeau mal nommé est l'endroit où git update-index --assume-unchangedstocke son état: https://stackoverflow.com/a/28657085/895245

    • Drapeau étendu 1 bit. Détermine si les indicateurs étendus sont présents ou non. Doit être 0sur la version 2 qui n'a pas d'indicateur étendu.

    • Drapeau d'étape 2 bits utilisé pendant la fusion. Les étapes sont documentées dans man git-merge:

      • 0: fichier normal, pas dans un conflit de fusion
      • 1: base
      • 2: les notres
      • 3: les leurs

      Lors d'un conflit de fusion, toutes les étapes de 1 à 3 sont stockées dans l'index pour permettre des opérations telles que git checkout --ours.

      Si vous git add, alors une étape 0 est ajoutée à l'index du chemin, et Git saura que le conflit a été marqué comme résolu. TODO: vérifiez ceci.

    • Longueur de 12 bits du chemin qui suivra 0 01:: 1 octet seulement depuis le cheminb

  • Indicateurs étendus de 2 octets. Uniquement significatif si le "drapeau étendu" a été défini sur les indicateurs de base. FAIRE.

  • 62(ASCII b): chemin de longueur variable. Longueur déterminée dans les drapeaux précédents, ici seulement 1 octet, b.

Vient ensuite un 00: 1 à 8 octets de remplissage nul de sorte que le chemin se termine par un zéro et que l'index se termine par un multiple de 8 octets. Cela se produit uniquement avant la version 4 de l'index.

Aucune extension n'a été utilisée. Git le sait car il n'y aurait pas assez d'espace libre dans le fichier pour la somme de contrôle.

Enfin, il y a une somme de contrôle de 20 octets ee 33 c0 3a .. 09 ab 49 94sur le contenu de l'index.


1
Très intéressant. +1. Cela illustre bien ma propre réponse . Je me demande si ces résultats changeraient avec le dernier Git 2.1+.
VonC le

3
@NielsBom oui, cela fonctionnerait aussi. Lors de l'interprétation des programmes, je préfère adopter deux approches: d'abord empirique pour voir quelles sorties il génère, et ensuite seulement lire la source. Sinon, on pourrait se retrouver pris dans des cas de bord de code source qui n'apparaissent même pas sur les sorties simples. Bien sûr, j'ai regardé les structures source pour m'aider à me guider, et chaque TODO peut être résolu en lisant comment ces structures sont manipulées, ce qui est la partie la plus difficile.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: Si je modifie l'index dans un éditeur hexadécimal et que je mets à jour sa somme de contrôle de 20 octets, y a-t-il une commande pour mettre à jour le sha1 qui est stocké dans d'autres objets? (git se plaint que la signature sha1 de l'index est corrompue) . Les données d'index sont également stockées d'une manière complètement différente lorsqu'elles sont envoyées via des demandes push.
user2284570

1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: à des fins de sécurité. Je cherche juste le type bien connu d'attaques de fichiers image raster appliquées à la base de données / aux objets git. (bien sûr, je sais que la plupart des implémentations ont récemment pris en compte cette perspective, mais probablement pas toutes).  Je recherche donc en particulier des structures de données binaires qui indiquent la longueur d'un tableau. (concernant les tampons de texte, il semble que la terminaison nulle soit la norme pour indiquer le nombre de lignes)
user2284570

1
En ce qui concerne git add, par votre TODO: vous avez raison. Si vous avez des entrées d'index de haut niveau (un conflit) à un chemin donné, lorsque vous git addce chemin, toutes les entrées d'index de haut niveau seront supprimées et la copie du répertoire de travail sera ajoutée à l'étape 0. (Résoudre le conflit).
Edward Thomson

11

L'index Git est une zone intermédiaire entre votre répertoire de travail et votre référentiel. Vous pouvez utiliser l'index pour créer un ensemble de modifications que vous souhaitez valider ensemble. Lorsque vous créez une validation, ce qui est validé est ce qui se trouve actuellement dans cet index, pas ce qui se trouve dans votre répertoire de travail.

Pour voir ce qu'il y a à l'intérieur de l'index, exécutez la commande:

git status

Lorsque vous exécutez git status, vous pouvez voir quels fichiers sont mis en scène (actuellement dans votre index), qui sont modifiés mais pas encore mis en scène, et lesquels sont complètement non suivis.

Vous pouvez lire ceci . Une recherche Google génère de nombreux liens, qui devraient être assez autonomes.


7
git statusne répertorie pas tous les fichiers de l'index. Il répertorie uniquement les fichiers qui diffèrent entre l'index et le répertoire de travail. Pour voir tous les fichiers dans l'index, vous devez utiliser git ls-files.
Akash Agrawal

1
@AkashAgrawal, git status fait dans la liste des fichiers d'index fait, indépendamment du fait qu'ils diffèrent entre l' indice et workdir.
Acumenus

3
oui, il répertorie CERTAINS fichiers d'index, mais il ne vous montre pas tout ce qui se trouve à l'intérieur de l'index, ce que dit sa déclaration dans sa réponse. C'est comme dire qu'il y a 2 boules vertes et 3 boules rouges dans une boîte. Pour voir ce qu'il y a à l'intérieur de la boîte, retirez les 2 boules vertes. Ce qu'Akash a dit est le plus précis, pour voir tous les fichiers dans l'index, utilisez git ls-files.
dave4jr

3
En effet. git statusrépertorie les fichiers qui se trouvent dans l'index, oui, mais ne répertorie pas tous les fichiers de l'index. Expliquer comment fonctionne git status réellement serait une réponse bénéfique à une question, mais probablement pas à celle-ci.
Edward Thomson

1
git statusaffiche l'état de l'arbre de travail (différence entre l'arbre de travail et l'index). Il ne montre pas réellement l'index. git-scm.com/docs/git-status
wisbucky

1

Voici ce dont vous aviez exactement besoin, utilisez cette commande.

$ 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

L'index Git est un fichier binaire (généralement conservé .git/index) contenant une liste triée de noms de chemins, chacun avec des autorisations et le SHA1 d'un objet blob;

git ls-filespeut vous montrer le contenu de l'index. Veuillez noter que les mots index, stageet cachesont la même chose dans Git: ils sont utilisés de manière interchangeable.

entrez la description de l'image ici

L'index Git, ou cache Git, a 3 propriétés importantes:

  1. L'index contient toutes les informations nécessaires pour générer un seul objet arborescent (déterminé de manière unique).
  2. L'index permet des comparaisons rapides entre l'objet d'arborescence qu'il définit et l'arborescence de travail.
  3. Il peut représenter efficacement des informations sur les conflits de fusion entre différents objets d'arborescence, permettant à chaque chemin d'être associé à des informations suffisantes sur les arbres impliqués pour que vous puissiez créer une fusion à trois voies entre eux.

Source :

  1. https://mincong.io/2018/04/28/git-index/
  2. https://medium.com/hackernoon/understanding-git-index-4821a0765cf
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.