git log, diff, show e blame: come leggere la cronologia di un progetto Git
git log mostra l'elenco dei commit e sa filtrarli per autore, data, file e testo; git diff confronta cartella di lavoro, index e qualsiasi commit; git show visualizza un commit per intero; git blame indica quale commit ha modificato per ultimo ogni riga di un file.
Quattro comandi coprono quasi tutte le domande sulla cronologia di un progetto. git log risponde a «cosa è successo», git diff a «cosa è cambiato esattamente», git show a «cosa c'è dentro un commit specifico», git blame a «chi ha scritto questa riga e quando». Di seguito, tecniche pratiche per ciascuno, con i flag che si usano davvero nello sviluppo quotidiano.
git log: l'elenco dei commit
Senza argomenti git log mostra i commit del branch corrente dal più recente al più vecchio: hash SHA-1 completo, autore, data e messaggio. Si scorre in un pager (di solito less): spazio per la pagina successiva, /testo per cercare, q per uscire.
commit 7be41d0c9a2e4f1b8d6c3e5a7f9b0c2d4e6f8a1b
Author: Anna Petrova <anna@example.com>
Date: Mon Oct 5 14:22:10 2026 +0300
feat: caching delle risposte API
Non serve copiare l'hash per intero: Git riconosce qualsiasi prefisso univoco da 4 caratteri in su, in pratica ne bastano 7.
Output compatto: --oneline
git log --oneline -10
# 7be41d0 (HEAD -> main, origin/main) feat: caching delle risposte API
# 1c02e8f fix: timeout delle richieste
# 9a4b3c2 refactor: client spostato in un modulo
Il flag -10 (o -n 10) limita il numero di commit. Tra parentesi ci sono i puntatori: dove si trovano HEAD, i branch locali e remoti, i tag.
Il grafo dei branch: git log --graph
Chi cerca «git graph» di solito intende proprio questo: la visualizzazione di diramazioni e merge direttamente nel terminale.
git log --oneline --graph --all
# * 3e1f0aa (feature/auth) feat: accesso tramite token
# | * 7be41d0 (HEAD -> main) feat: caching delle risposte API
# |/
# * 1c02e8f fix: timeout delle richieste
# * 5d2c7b1 Merge branch 'feature/search'
# |\
# | * 8f3a9e0 feat: ricerca
# |/
# * 9a4b3c2 refactor: client spostato in un modulo
--all mostra tutti i branch, non solo quello corrente. Conviene creare un alias: git config --global alias.lg "log --oneline --graph --all --decorate", dopodiché basta git lg.
Formato personalizzato: --pretty=format
git log --pretty=format:"%h %ad %an %s" --date=short
# 7be41d0 2026-10-05 Anna Petrova feat: caching delle risposte API
I segnaposto principali: %h hash breve, %H completo, %an autore, %ae la sua e-mail, %ad data dell'autore, %ar data relativa («2 days ago»), %s titolo del messaggio.
Come filtrare la cronologia con git log
Per autore e data
git log --author="Anna"
git log --since="2 weeks ago" --until="2026-10-01"
git log --since=yesterday --oneline
--author accetta un'espressione regolare e cerca sia nel nome sia nell'e-mail. Git capisce le date sia in forma libera sia in formato ISO.
Per testo del messaggio
git log --grep="fix" -i --oneline
-i rende la ricerca insensibile alle maiuscole. Se il vostro team scrive i numeri dei ticket nei messaggi, così trovate subito tutti i commit di un'attività.
Per file o cartella
git log --oneline -- src/api/client.py
git log --follow -p -- src/api/client.py
Il doppio trattino separa i percorsi dai branch. --follow segue la cronologia del file anche attraverso le rinomine (funziona per un solo file), -p mostra la patch di ogni commit.
Per codice modificato: la ricerca «piccone»
git log -S "retry_count" --oneline # commit in cui è cambiato il numero di occorrenze della stringa
git log -G "timeout\s*=" --oneline # commit con righe nel diff che corrispondono alla regex
-S trova il commit in cui una funzione o variabile è stata aggiunta o rimossa: insostituibile quando dovete capire dove è finito un pezzo di codice.
Intervalli di commit
git log main..feature # cosa c'è in feature ma non in main
git log origin/main..HEAD # i miei commit locali non ancora inviati
git log --no-merges # senza merge commit
git log --stat # quali file e quante righe sono stati modificati
git diff: cosa è cambiato esattamente
La cosa principale da capire su git diff è quali due stati confronta. La confusione su questo punto è all'origine della domanda «perché il diff è vuoto, ho cambiato tutto».
| Comando | Cosa confronta |
|---|---|
git diff | cartella di lavoro rispetto all'index (modifiche non preparate) |
git diff --staged (--cached) | index rispetto all'ultimo commit (cosa entrerà nel commit) |
git diff HEAD | cartella di lavoro rispetto all'ultimo commit (tutto insieme) |
git diff A B | due commit, branch o tag |
git diff A...B | le modifiche in B dal momento della diramazione da A |
Se avete fatto git add, il normale git diff diventa vuoto: le modifiche sono già nell'index, guardate --staged. I file nuovi, mai aggiunti, il diff non li mostra affatto.
Come leggere l'output del diff
diff --git a/config.py b/config.py
index 3b18e51..a1c4f02 100644
--- a/config.py
+++ b/config.py
@@ -10,7 +10,7 @@ DEFAULTS = {
"host": "localhost",
- "timeout": 5,
+ "timeout": 30,
"retries": 3,
Le righe con - sono state rimosse, quelle con + aggiunte, le altre sono contesto. L'intestazione @@ -10,7 +10,7 @@ significa: il frammento inizia alla riga 10 e occupa 7 righe nella versione vecchia e in quella nuova.
Flag utili di git diff
git diff --stat main feature # riepilogo per file
git diff --name-only HEAD~3 # solo i nomi dei file modificati
git diff --word-diff # modifiche parola per parola, comodo per i testi
git diff -w # ignorare le modifiche agli spazi
git diff main feature -- src/ # limitare a una cartella
Prima di ogni commit è utile guardare git diff --staged: è l'ultima occasione per notare un print di debug o un file aggiunto per sbaglio.
git show: un commit per intero
git show mostra i metadati del commit e il suo diff rispetto al genitore. Senza argomenti, l'ultimo commit.
git show 7be41d0
git show HEAD~2 --stat # senza patch, solo il riepilogo
git show v1.2.0 # tag: annotazione e commit
git show main:src/config.py # il file com'era in quel commit
L'ultima forma <revisione>:<percorso> è particolarmente utile: permette di vedere una vecchia versione del file senza passare su di essa. Reindirizzate l'output in un file e recupererete il contenuto eliminato senza checkout.
git blame: chi ha modificato questa riga
git blame file mostra per ogni riga l'ultimo commit che l'ha modificata, l'autore e la data. Il nome suona accusatorio, ma in realtà è uno strumento per trovare il contesto: individuare il commit, leggerne il messaggio e capire perché è stato fatto così.
git blame -L 40,60 src/api/client.py
# 1c02e8f3 (Anna Petrova 2026-09-28 11:04:51 +0300 41) timeout = settings.timeout
# 9a4b3c2e (Ivan Smirnov 2026-09-14 18:30:02 +0300 42) session = build_session()
-L 40,60: solo un intervallo di righe; funziona anche-L :nome_funzione.-w: ignorare le modifiche agli spazi, per non finire sui commit di formattazione.-C: seguire le righe spostate da altri file.--ignore-rev <hash>o il file.git-blame-ignore-revs: saltare commit massivi come la formattazione automatica.
Scenario tipico di indagine: git blame trova il commit, git show lo mostra per intero, git log sul file dà le modifiche vicine.
Navigare nel passato: HEAD~ e HEAD^
Ai commit ci si può riferire non solo con gli hash. HEAD~1 è il genitore del commit corrente, HEAD~3 il bisnonno. HEAD^2 è il secondo genitore di un merge commit. Funzionano anche i nomi di branch, tag e branch remoti: origin/main~2. Per vedere l'intero progetto a un vecchio commit si usa git switch --detach <hash>, per tornare git switch -.
Cronologia buona e cronologia cattiva
Tutti questi comandi sono utili tanto quanto è sensata la cronologia. Messaggi come «fix», «wip», «altre modifiche» rendono inutili git log --grep e git blame. Un buon commit è una sola modifica logica con un titolo che spiega cosa e perché: fix: timeout API aumentato a 30 s per il gateway lento. Fra sei mesi sarà proprio un commit così che blame troverà, facendovi risparmiare un'ora.
In pratica: indagare su un bug attraverso la cronologia
Supponiamo che dopo l'ultima release le richieste all'API abbiano iniziato a fallire per timeout. Ecco come la combinazione dei comandi porta alla causa in un paio di minuti.
- Guardiamo cosa è entrato nella release:
git log v1.4.0..v1.5.0 --oneline. L'elenco è breve, ma dai titoli il colpevole non è evidente. - Restringiamo per file:
git log v1.4.0..v1.5.0 --oneline -- src/api/. Restano due commit. - Cerchiamo nel codice:
git log -S "timeout" --oneline -- src/api/trova il commit in cui è cambiato il valore del timeout. - Lo guardiamo per intero:
git show 1c02e8f. Dal diff si vede che il timeout è stato ridotto da 30 a 5 secondi, e il messaggio spiega «velocizziamo la risposta della UI». - Controlliamo chi altro ha toccato quella riga:
git blame -L :build_session src/api/client.py.
Da qui la soluzione è ingegneristica: ripristinare il valore, spostare il timeout nelle impostazioni o annullare il commit con git revert. Se invece i commit sono centinaia e trovare il colpevole a occhio è impossibile, viene in aiuto git bisect: una ricerca binaria nella cronologia che in pochi passi indica il commit che ha rotto il comportamento.
Impostazioni che semplificano la vita
git config --global log.date iso # formato delle date in log
git config --global diff.colorMoved zebra # evidenziare le righe spostate nel diff
git config --global core.pager "less -FRX" # non aprire il pager per output brevi
Se l'output deve essere elaborato da uno script, disattivate colori e pager: git --no-pager log --format="%H %s" --no-color. Per l'elaborazione automatica usate l'hash completo %H: i prefissi brevi col tempo possono diventare ambigui in un repository grande.
Riepilogo
git log con i filtri --oneline, --graph, --author, -S e i percorsi risponde alla domanda «cosa è successo». git diff confronta cartella di lavoro, index e commit: l'importante è ricordare cosa confronta per impostazione predefinita. git show apre un singolo commit o una vecchia versione di un file, e git blame porta da una riga di codice alla decisione che l'ha generata. La lettura della cronologia e la navigazione tra i commit sono affrontate in pratica nel corso su Git.
Domande frequenti
Come uscire da git log?
Premete q: l'output è aperto nel pager less. Per stampare senza pager usate git --no-pager log oppure il flag -n con un numero piccolo.
Come vedere la cronologia di un file eliminato?
Eseguite git log --oneline -- percorso/del/file (con il doppio trattino), e per il contenuto prima dell'eliminazione git show <hash>^:percorso/del/file.
Come confrontare un branch locale con quello remoto?
Prima git fetch, poi git diff origin/main oppure git log origin/main..HEAD per vedere i vostri commit non ancora inviati.
Esiste una visualizzazione grafica della cronologia?
Sì, insieme a Git viene fornito gitk, e il grafo della cronologia è integrato in VS Code, negli IDE JetBrains e nelle interfacce web di GitHub e GitLab.
Perché git diff non mostra nulla?
Molto probabilmente le modifiche sono già state aggiunte all'index con git add: guardate git diff --staged. I nuovi file non tracciati git diff non li mostra affatto.
Questo argomento è trattato in modo approfondito, con pratica, nel corso «Git da zero a sviluppatore sicuro».
Vai al corso