modulo 01 / lezione 01

Fondamenti e modello mentale

Cosa è Git: snapshot, non diff

Sostituire l'idea di 'Git che salva differenze' con il modello reale: ogni commit è uno snapshot completo dell'albero di file.

60 min Git e controllo versione

Cosa è Git: snapshot, non diff

La prima idea da correggere è questa: Git non salva una sequenza di differenze testuali come se fosse un documento con revisioni. Git salva snapshot. Ogni commit punta a una fotografia completa dell’albero dei file in quel momento.

Questo non significa che Git sprechi spazio copiando tutto ogni volta. Internamente deduplica oggetti identici, comprime e ottimizza. Ma il modello mentale corretto resta: quando fai commit, Git registra “com’era il progetto”, non solo “cosa è cambiato”.

Perché questa lezione conta

Se pensi a Git come a una lista di patch, molti comandi sembrano magia: branch, merge, reset, rebase, checkout. Se lo pensi come un grafo di snapshot collegati da puntatori, i comandi diventano più prevedibili.

Questa lezione serve a togliere superstizione. Git è difficile quando lo usi a memoria. Diventa molto più maneggevole quando sai che stai manipolando oggetti immutabili e riferimenti mobili.

Obiettivo operativo

Alla fine della lezione devi saper spiegare cosa contiene un commit, quali oggetti lo compongono e perché un branch può spostarsi senza “contenere” davvero codice.

Snapshot, non patch

Immagina tre commit:

A -- B -- C

Ogni commit punta a un tree, cioè a una struttura che rappresenta cartelle e file. Se tra A e B cambia solo un file, Git non deve duplicare ogni contenuto: può riusare gli oggetti dei file invariati. Ma il commit B descrive comunque lo stato completo del progetto.

Questo spiega perché puoi fare checkout di un commit vecchio e vedere tutto il progetto com’era allora. Git non ricostruisce solo applicando patch una dopo l’altra nel tuo editor: legge lo snapshot puntato dal commit.

Gli oggetti principali

Git lavora con pochi tipi di oggetti:

Blob. Contenuto di un file. Non contiene il nome del file, solo i byte.

Tree. Directory: associa nomi, permessi e riferimenti a blob o altri tree.

Commit. Punta a un tree, ha zero o più parent, autore, committer, data e messaggio.

Tag. Riferimento, spesso annotato, a un commit o a un oggetto.

Il nome file vive nel tree, non nel blob. Questo dettaglio è utile: se rinomini un file senza cambiarne contenuto, Git può riconoscere che il contenuto è lo stesso anche se il percorso cambia.

Hash come identità

Ogni oggetto Git ha un hash. L’hash dipende dal contenuto e dal tipo dell’oggetto. Se cambi un byte, cambia l’identità.

Questo dà tre proprietà operative:

  1. integrità: Git sa se un oggetto è stato corrotto;
  2. deduplicazione: contenuti identici hanno lo stesso oggetto;
  3. immutabilità pratica: riscrivere un commit significa creare un nuovo commit con nuovo hash.

Quando fai rebase, amend o squash, non stai “modificando” commit esistenti. Stai creando nuovi commit simili, con hash diversi, e poi sposti un branch a puntare lì.

Comandi essenziali

git init demo-git-snapshot
cd demo-git-snapshot
git config user.name "Demo"
git config user.email "demo@example.com"

echo "prima versione" > app.txt
git add app.txt
git commit -m "Aggiungi app iniziale"

echo "seconda versione" > app.txt
git add app.txt
git commit -m "Aggiorna testo app"

git cat-file -p HEAD
git cat-file -p HEAD^{tree}
git ls-tree -r HEAD

git cat-file -p HEAD mostra il commit: vedrai il tree, il parent, autore e messaggio. git ls-tree -r HEAD mostra la fotografia dei file puntata da quel commit.

Laboratorio guidato

Crea un repo demo con due file e tre commit:

  1. primo commit con README.md;
  2. secondo commit che aggiunge app.txt;
  3. terzo commit che modifica solo app.txt.

Per ogni commit annota:

  1. hash del commit;
  2. hash del tree;
  3. blob associati ai file;
  4. cosa resta uguale tra commit consecutivi.

Poi disegna il grafo:

commit C -> tree C -> blob README
                    -> blob app v2
commit B -> tree B -> blob README
                    -> blob app v1

Non serve essere perfetti nel disegno. Serve vedere che il commit punta a una fotografia.

Output atteso

Produci una nota tecnica breve:

Git salva snapshot.
Un commit punta a un tree.
Un tree collega nomi file a blob.
Un branch punta a un commit.
Riscrivere storia crea nuovi commit, non cambia quelli vecchi.

Questa nota diventa la base mentale del resto del corso.

Errori comuni

Pensare che un branch sia una cartella. Un branch è un puntatore mobile a un commit.

Pensare che amend modifichi davvero il commit. Crea un nuovo commit e sposta il branch.

Confondere diff e storia. Il diff è una vista calcolata tra due snapshot, non l’unità primaria salvata da Git.

Checklist di verifica

  • so distinguere blob, tree e commit;
  • so leggere git cat-file -p HEAD;
  • so spiegare perché due commit simili hanno hash diversi;
  • so dire perché Git può recuperare un progetto com’era in un commit vecchio.

Collegamenti

  • Modulo: Fondamenti e modello mentale — lezione 1 del corso.
  • La prossima lezione porta questo modello dentro working tree, index e repository.