Introduction
Le dépôt de Git est, en son cœur, un magasin d'objets adressé par contenu. Il existe exactement quatre types d'objets : blob, tree, commit et tag. Chaque opération finit par les toucher. Comprendre ces quatre types démystifie la majeure partie de Git.
Blobs
Un blob stocke le contenu d'un fichier, rien de plus. Pas de nom de fichier, pas de permissions, pas d'historique. Deux fichiers au contenu identique partagent un seul blob, peu importe où ils vivent dans l'arbre.
echo "hello" | git hash-object --stdin
# ce013625030ba8dba906f756967f9e9ca394464a
Trees
Un tree est un listing de répertoire : un ensemble trié d'entrées (mode, type, sha, name). Les sous-répertoires sont eux-mêmes des trees, récursivement. Chaque commit pointe vers exactement un tree racine.
git ls-tree HEAD
# 100644 blob a1b2... README.md
# 040000 tree c3d4... src
Commits
Un objet commit contient :
- Un pointeur vers un tree racine.
- Zéro ou plusieurs commits parents (zéro pour la racine, deux ou plus pour les merges).
- Auteur et committer avec horodatages.
- Un message.
- Signature GPG/SSH optionnelle.
git cat-file -p HEAD
# tree 9f1a...
# parent b2c3...
# author Ada <[email protected]> 1714300000 +0000
# committer Ada <[email protected]> 1714300000 +0000
#
# Add greeting
Tags
Un tag annoté est son propre objet pointant vers un autre objet (presque toujours un commit), avec les infos du tagger et un message. Les tags lightweight sont juste des refs et n'ont pas d'objet.
git cat-file -t v1.0.0
# tag
git cat-file -p v1.0.0
Mettre tout ensemble
Parcourez l'arbre d'un commit manuellement :
git cat-file -p HEAD^{tree}
git cat-file -p HEAD^{tree}:src
git cat-file -p HEAD:README.md
Le déréférencement ^{tree} et la syntaxe commit:path sont la façon dont tous les outils Git naviguent.
Stockage
Chaque objet est compressé avec zlib et adressé par le SHA-1 (ou SHA-256) de son contenu non compressé plus un en-tête. Le contenu identique, n'importe où dans l'historique, est dédupliqué automatiquement.
Modes des entrées de tree
Le champ mode dans une entrée de tree est un petit ensemble de modes de fichiers de type POSIX :
100644: fichier normal non exécutable (blob).100755: fichier exécutable (blob).120000: lien symbolique (blob dont le contenu est la cible).040000: sous-répertoire (tree).160000: gitlink (référence sous-module vers un SHA de commit).
git ls-tree HEAD
git update-index --chmod=+x scripts/run.sh
git ls-tree HEAD scripts/
Git est intentionnellement limité ; les permissions et la propriété arbitraires ne sont pas stockées.
Erreurs fréquentes
Croire que Git stocke des diffs. Ce n'est pas le cas ; il stocke des instantanés complets, dédupliqués par hachage et plus tard delta-compressés dans les pack files. Confondre les trees avec les répertoires sur disque ; les trees sont des objets immuables. Confondre les tags lightweight avec les annotés ; seuls les tags annotés portent des métadonnées et des signatures. Enfin, s'attendre à ce que renommer un fichier change le blob ; le blob est le même, seule l'entrée de nom du tree change. Passez dix minutes avec git cat-file -p sur un vrai dépôt et le modèle deviendra une seconde nature.