Modulo 18 — Git dietro le quinte
Cosa contiene davvero la cartella .git? I file più interessanti:
.git/├── config ├── HEAD ├── index├── refs/ └── objects/ (+ altro)config
Section titled “config”Il file di configurazione per-repo: abbiamo visto le impostazioni globali (--global, nome ed email), ma qui dentro stanno le impostazioni valide solo per questo repository.
La cartella refs
Section titled “La cartella refs”Contiene la cartella heads/: un file per ogni branch, dal nome del branch stesso, che contiene l’hash del commit alla punta del branch. Es. refs/heads/master contiene l’hash dell’ultimo commit di master.
C’è anche refs/tags/: un file per ogni tag.
Un semplice file di testo che registra dove punta HEAD:
- contiene
refs/heads/master→ HEAD punta al branch master; - in detached HEAD contiene invece direttamente un hash di commit.
Un file binario che elenca i file tracciati dal repository, con i loro metadati. Nota: non contiene il contenuto dei file, solo riferimenti.
La cartella objects
Section titled “La cartella objects”Il vero magazzino: qui Git salva tutto — i backup dei file, i commit e altro. I file sono compressi e cifrati, quindi appaiono illeggibili.
Gli hash
Section titled “Gli hash”Git si basa su funzioni di hashing: mappe che trasformano input di dimensione arbitraria in output a dimensione fissa.
Le funzioni hash crittografiche hanno queste proprietà:
- funzione one-way: non si può ricostruire l’input dall’output;
- una piccola modifica dell’input genera un output molto diverso;
- deterministiche: stesso input → stesso output;
- collisioni estremamente improbabili (due input diversi con lo stesso output).
SHA-1 è la funzione usata da Git (destinata a cambiare in futuro):
- genera sempre numeri esadecimali di 40 cifre;
- i “commit hash” che vediamo ovunque sono l’output di SHA-1.
Git come database chiave-valore
Section titled “Git come database chiave-valore”Git è in sostanza uno store chiave-valore: gli passi qualunque contenuto e ti restituisce una chiave univoca (l’hash SHA-1) con cui ritirare quel contenuto in futuro.
echo 'hello' | git hash-object --stdin # calcola (e stampa) la chiaveecho 'hello' | git hash-object --stdin -w # -w: scrive davvero l'oggetto nel databasegit cat-file -p <hash> # ritira il contenuto (-p = pretty print)$ echo 'hello' | git hash-object --stdin -wce013625030ba8dba906f756967f9e9ca394464a$ git cat-file -p ce013625030ba8dba906f756967f9e9ca394464ahelloContenuti diversi (es. hello vs goodbye) producono chiavi diverse: ogni versione di un file è un oggetto distinto.
I 4 tipi di oggetti
Section titled “I 4 tipi di oggetti”| Tipo | Cosa contiene |
|---|---|
| blob | Il contenuto di un file — nient’altro. Non contiene nemmeno il nome del file |
| tree | Il contenuto di una directory: puntatori a blob e ad altri tree, con mode, tipo e filename |
| commit | Un tree + il contesto: commit genitore/i, autore, committer, messaggio |
| annotated tag | L’oggetto del tag annotato |
I tree
Section titled “I tree”Ogni entry di un tree contiene l’hash SHA-1 di un blob o di un altro tree, più mode, tipo e nome. Si ispeziona così:
git cat-file -p master^{tree} # il tree puntato dalla punta di masterLa struttura è ricorsiva: un tree può contenere blob (file) e sotto-tree (sottodirectory), che a loro volta contengono blob e tree — fino ai contenuti finali.
I commit
Section titled “I commit”Quando esegui git commit, Git crea un commit object:
- tree = lo stato attuale dell’index (la fotografia della directory);
- parent = il commit corrente puntato da HEAD;
- autore, committer e messaggio.
La history è così una catena di commit, ognuno legato al genitore — da cui l’annotazione (HEAD -> master) nel log.
Il commit punta al suo tree; il tree aggrega i blob dei file; i commit si collegano tra loro tramite i genitori.
A ogni commit, Git salva un nuovo tree; i blob invariati vengono riuscita (stesso hash), quindi ogni snapshot costa solo ciò che è cambiato.
Annotated tag
Section titled “Annotated tag”Il quarto tipo di oggetto: l’oggetto generato dai tag annotati, con metadati e messaggio.
In sintesi
Section titled “In sintesi”- Ogni versione di ogni file → blob (identificato dal suo hash SHA-1).
- Ogni directory → tree che aggrega blob e sotto-tree.
- Ogni snapshot → commit che punta a un tree e al commit genitore.
- Branch e tag → semplici file in
refs/che contengono hash. HEAD→ un file che dice a quale ref si sta lavorando.
Immagini: documentazione ufficiale di Git (git-scm.com, dal libro Pro Git di Scott Chacon), licenza CC BY-NC-SA 3.0.