Introduction
Le modèle adressé par contenu de Git déduplique les objets identiques, mais les blobs similaires-mais-pas-identiques (un fichier et son édition ultérieure) coûteraient toujours leur taille complète chacun. Les pack files résolvent cela avec la compression delta : stocker un objet comme une base plus une séquence d'instructions « copy/insert » qui produisent un autre objet.
Comment cela fonctionne
Lors du packing, Git compare les objets candidats (typiquement des blobs de taille et type similaires) et choisit une base pour chacun. Le delta enregistre :
- L'objet base (par offset dans le pack ou par SHA).
- Tailles de la base et de la cible.
- Un flux d'instructions copy (utiliser des octets de la base) et insert (octets littéraux).
Le flux delta est ensuite zlib-compressé.
Inspecter les deltas
git verify-pack -v .git/objects/pack/pack-<hash>.idx | head -20
Les colonnes de sortie incluent la taille packée, la profondeur et le SHA de base pour les entrées delta. Un objet non-delta n'a pas de base.
Réglages
git config pack.window 250 # candidats examinés par objet
git config pack.depth 50 # longueur de chaîne max
git config pack.threads 4
git config pack.windowMemory 100m
git config pack.deltaCacheSize 256m
pack.window contrôle l'agressivité avec laquelle Git cherche de bonnes bases ; pack.depth limite la longueur des chaînes de delta.
Repack agressif vs normal
git repack -a -d # standard
git repack -a -d --depth=250 --window=250 # agressif
git gc --aggressive
Les repacks agressifs jettent les deltas existants et recalculent à partir de zéro, coûtant du CPU mais améliorant possiblement le résultat.
Atteignabilité et bitmaps
Les serveurs combinent souvent le packing delta avec les bitmaps d'atteignabilité pour un calcul rapide d'ensemble de clones :
git repack -adb
Pourquoi certains objets ne sont pas deltifiés
- Données cryptographiquement aléatoires (déjà incompressibles).
- Objets dont les seuls candidats sont plus petits que le seuil configuré.
- Objets hors de la portée de la fenêtre du pack.
Deltas inter-pack
Les index multi-pack (git multi-pack-index) plus le mode de repack --geometric (Git 2.33+) permettent de garder efficacement des deltas entre plusieurs packs :
git repack --geometric=2 -d
C'est le schéma recommandé pour les gros dépôts.
Îlots de delta
Pour les opérateurs de serveur hébergeant de nombreux forks du même projet, les îlots de delta partitionnent les objets pour que les deltas ne se produisent qu'à l'intérieur de l'ensemble de refs d'un fork, permettant le clone rapide de tout fork unique :
git config pack.island "refs/remotes/(.*)/heads"
git config pack.islandCore "main"
git repack -adb
Sans îlots, un objet atteignable seulement depuis le fork A pourrait être deltifié contre un objet atteignable seulement depuis le fork B ; servir le clone du fork A nécessiterait alors d'envoyer aussi les objets de B. La plupart des utilisateurs n'en ont jamais besoin, mais c'est la sauce secrète derrière la performance des pack servers de GitHub, GitLab et Bitbucket.
Erreurs fréquentes
Supposer que les deltas sont avant (plus récent = base) ou arrière (plus ancien = base) ; Git est agnostique et choisit ce qui produit le plus petit delta. Copier des packs entre des dépôts avec différents préfixes SHA ; les données sont adressées par contenu donc c'est correct, mais renommer des fichiers basés sur des hachages partiels peut casser. Définir pack.depth absurdement haut pour des packs petits ; des chaînes plus profondes signifient un accès aux objets plus lent (chaque delta dans la chaîne doit être appliqué). Enfin, attendre que la compression delta économise de l'espace sur des binaires déjà compressés (vidéos, JPGs) ; ça ne le fait presque jamais. Utilisez Git LFS pour ceux-ci.