Introduzione
Git nomina ogni oggetto con l'hash crittografico del suo contenuto. Questo è storage indirizzato per contenuto: il nome è l'impronta digitale del contenuto. L'hash predefinito è SHA-1 (160 bit, 40 caratteri esadecimali). Il supporto per SHA-256 esiste sperimentalmente da Git 2.29.
Come viene calcolato un hash
Git antepone un header della forma <type> <size>\0 al contenuto grezzo, poi lo hasha:
printf 'blob 6\0hello\n' | sha1sum
# ce013625030ba8dba906f756967f9e9ca394464a -
Lo stesso valore esce da git hash-object:
printf 'hello\n' | git hash-object --stdin
# ce013625030ba8dba906f756967f9e9ca394464a
Perché l'indirizzamento per contenuto
- Deduplicazione: contenuti identici memorizzati una sola volta.
- Integrità: qualsiasi corruzione cambia l'hash, immediatamente rilevabile.
- Riproducibilità: lo stesso tree ha sempre lo stesso nome.
- Sync distribuito: Git può chiedere "hai
abc123?" senza spiegare cosa sia.
Hash abbreviati
Git accetta il prefisso più corto non ambiguo, normalmente 7 caratteri. Man mano che un repo cresce, possono servire più cifre:
git rev-parse --short HEAD
git rev-parse --short=12 HEAD
git config --global core.abbrev 12
SHA-1 contro SHA-256
SHA-1 ha attacchi di collisione noti (SHAttered, 2017). Il progetto Git ha risposto con SHA-256 come formato oggetto alternativo. Per creare un repo SHA-256:
git init --object-format=sha256
Nota: i repo SHA-1 e SHA-256 non possono ancora interoperare; il supporto di tooling e hosting sta ancora maturando da Git 2.45+. Per ora, la maggior parte dei progetti continua con SHA-1, integrato dall'implementazione SHA-1 di Git con rilevamento di collisioni.
Verificare l'integrità
git fsck --full
git fsck --strict
git fsck ricalcola gli hash per ogni oggetto e segnala qualsiasi mismatch.
Ispezionare un oggetto
git cat-file -t <sha> # tipo
git cat-file -s <sha> # dimensione
git cat-file -p <sha> # contenuto pretty-printed
SHA-1 con hardening
Dal 2017 Git è distribuito con un'implementazione SHA-1 "con rilevamento collisioni" (sha1dc) che riconosce il pattern SHAttered pubblicato e rifiuta di hashare tali input. Questo rende gli attacchi pratici contro i repository Git essenzialmente impossibili senza scoprire una nuova tecnica di collisione. Il costo è un piccolo rallentamento sull'hashing; puoi optare per OpenSSL SHA-1 standard con ./configure --with-openssl-sha1 quando compili dai sorgenti, ma pochi utenti hanno motivo di farlo.
git --version --build-options 2>&1 | grep -i sha
Errori comuni
Preoccuparsi che le collisioni SHA-1 compromettano il tuo repo. Gli attacchi noti richiedono input forgiati; Git inoltre rileva il pattern di collisione pubblicato. Il rischio pragmatico per un progetto normale è essenzialmente zero. Troncare gli hash troppo aggressivamente negli script; in un repo con un milione di oggetti, 7 caratteri possono collidere. Usa git rev-parse --short per lasciare scegliere a Git. Modificare i file oggetto direttamente sotto .git/objects; questo rompe l'invariante di indirizzamento per contenuto e corrompe il repo. Tutte le scritture devono passare attraverso il plumbing di Git.