Introducción
El modelo direccionado por contenido de Git deduplica objetos idénticos, pero blobs similares-pero-no-idénticos (un archivo y una edición posterior) seguirían costando tamaño completo cada uno. Los archivos pack resuelven esto con compresión delta: almacenan un objeto como una base más una secuencia de instrucciones "copy/insert" que producen otro objeto.
Cómo funciona
Al empaquetar, Git compara objetos candidatos (típicamente blobs de tamaño y tipo similar) y elige una base para cada uno. El delta registra:
- El objeto base (por offset dentro del pack o por SHA).
- Tamaños de base y destino.
- Un flujo de instrucciones copy (usar bytes de la base) e insert (bytes literales).
El flujo delta luego se comprime con zlib.
Inspeccionando deltas
git verify-pack -v .git/objects/pack/pack-<hash>.idx | head -20
Las columnas de salida incluyen tamaño empaquetado, profundidad y SHA base para entradas delta. Un objeto no-delta no tiene base.
Ajustables
git config pack.window 250 # candidatos examinados por objeto
git config pack.depth 50 # longitud máxima de cadena
git config pack.threads 4
git config pack.windowMemory 100m
git config pack.deltaCacheSize 256m
pack.window controla qué tan agresivamente Git busca buenas bases; pack.depth limita cuán largas pueden crecer las cadenas delta.
Repack agresivo vs normal
git repack -a -d # estándar
git repack -a -d --depth=250 --window=250 # agresivo
git gc --aggressive
Los repacks agresivos descartan los deltas existentes y los recalculan desde cero, costando CPU pero posiblemente mejorando el resultado.
Alcanzabilidad y bitmaps
Los servidores a menudo combinan empaquetamiento delta con bitmaps de alcanzabilidad para cálculo rápido de conjuntos de clone:
git repack -adb
Por qué algunos objetos no se deltifican
- Datos criptográficamente aleatorios (ya incomprimibles).
- Objetos cuyos únicos candidatos son más pequeños que el umbral configurado.
- Objetos más allá del alcance de la pack window.
Deltas entre packs
Los multi-pack indexes (git multi-pack-index) más el modo de repack --geometric (Git 2.33+) hacen posible mantener deltas entre muchos packs eficientemente:
git repack --geometric=2 -d
Este es el esquema recomendado para repositorios grandes.
Delta islands
Para operadores de servidor que alojan muchos forks del mismo proyecto, las delta islands particionan objetos para que los deltas solo ocurran dentro del conjunto de refs de un fork, permitiendo el clone rápido de cualquier fork individual:
git config pack.island "refs/remotes/(.*)/heads"
git config pack.islandCore "main"
git repack -adb
Sin islands, un objeto alcanzable solo desde el fork A podría ser deltificado contra un objeto solo alcanzable desde el fork B; servir el clone del fork A entonces requeriría enviar también objetos de B. La mayoría de usuarios nunca necesitan esto, pero es la salsa secreta detrás del rendimiento del pack server de GitHub, GitLab y Bitbucket.
Errores comunes
Asumir que los deltas son hacia adelante (más nuevo = base) o hacia atrás (más viejo = base); Git es agnóstico y elige cualquiera que produzca el delta más pequeño. Copiar packs entre repos con prefijos SHA diferentes; los datos están direccionados por contenido así que está bien, pero renombrar archivos basados en hashes parciales puede romper. Establecer pack.depth absurdamente alto en busca de packs pequeños; cadenas más profundas significan acceso a objetos más lento (cada delta en la cadena debe aplicarse). Finalmente, esperar que la compresión delta ahorre espacio en binarios ya comprimidos (videos, JPGs); casi nunca lo hace. Usa Git LFS para esos.