modulo 04 / lezione 22
Isolare la causa
Ricerca binaria nel codice e nei commit
Tagliare lo spazio di ricerca con confronti a metà, diff e cronologia Git. Usare git bisect interattivo e git bisect run con uno script di verifica.
In parole semplici
Tra il primo commit “funzionava” e l’ultimo “non funziona più”, c’è una storia di N commit. Trovare quale ha introdotto il bug a mano significa controllarli a uno a uno. La ricerca binaria li controlla in log₂(N) passi: 1024 commit in 10 passi, 1.000.000 in 20.
Git mette a disposizione git bisect, automatizzabile con uno script. È lo strumento più potente del modulo “isolare”.
Parole nuove
- bisezione: tecnica di ricerca che dimezza lo spazio ad ogni passo.
- bug good / bad: commit in cui il bug non c’è (good) o c’è (bad).
- bisect run: modalità automatica di
git bisectcon uno script di test. - commit incolpato: commit identificato come responsabile.
Cosa impari
- Eseguire una
git bisectmanuale a fini didattici. - Scrivere uno script che
git bisect runpuò usare in automatico. - Risparmiare ore su bug nascosti tra molti commit.
Lo schema della bisezione
Hai due punti certi:
- Commit A: il bug non c’è.
- Commit B: il bug c’è.
In mezzo c’è la sequenza dei commit. Procedura:
- Vai al commit a metà strada (
M). - Verifica se il bug c’è.
- Sì → la responsabilità è tra A (escluso) e M.
- No → la responsabilità è tra M (escluso) e B.
- Ripeti sul nuovo intervallo.
Dopo k passi, lo spazio è ridotto di un fattore 2^k. 16 commit → 4 passi. 1000 → ~10.
git bisect manuale
Procedura:
git bisect start
git bisect bad # HEAD corrente è "bad"
git bisect good <commit-A> # commit "buono" noto
Git ti porta automaticamente al commit di mezzo. Tu provi:
# costruisci, esegui, controlla il bug
git bisect good # se bug NON presente
# oppure
git bisect bad # se bug presente
Git ti porta al prossimo punto di mezzo. Vai avanti fino a:
<commit-XYZ> is the first bad commit
Per chiudere:
git bisect reset
git bisect automatico (bisect run)
Per gli amanti dell’efficienza: uno script che ritorna 0 se “good” e diverso da 0 se “bad”. Git ci itera.
git bisect start
git bisect bad
git bisect good <commit-A>
git bisect run ./check-bug.sh
Esempio di check-bug.sh:
#!/bin/bash
set -e
npm install --silent
npm run build --silent
# eseguo il test che fallisce solo se il bug è presente
node ./tests/regression-142.js
Se il test esce con 0, Git marca il commit “good”. Se esce con 1, “bad”. Se esce con 125, “skip” (commit non testabile, es. non compila).
Risultato: in dieci minuti Git trova il colpevole tra 200 commit, senza che tu tocchi tastiera.
Esempio realistico
Scenario: regressione nel carrello, scoperta venerdì. Sai che martedì funzionava. In mezzo 47 commit.
git bisect start
git bisect bad HEAD
git bisect good v2.3.0 # tag martedì
Git porta al commit #24. Provi: il bug c’è. git bisect bad. Va al #12. Provi: non c’è. git bisect good. Va al #18. Provi: c’è. E così via.
Sei passaggi dopo:
commit abc1234 is the first bad commit
Author: ...
Date: ...
Refactor carrello.calculateTotal
Da qui hai il commit. Il fix può essere git revert abc1234 (modulo 5) oppure un’indagine mirata su quelle 30 righe.
Saltare commit non testabili
A volte un commit in mezzo non compila (refactor parziale). Marcalo skip:
git bisect skip
Git lo evita e prova il vicino.
Non solo git bisect: bisezione nel codice
La stessa logica si applica a:
- File grande: commenta metà, vedi se il bug resta.
- Dati grandi: usa metà dei record, vedi se il bug resta.
- Pipeline: spegni metà degli step.
git bisect è l’applicazione a Git di un’idea generale.
Esercizio guidato
In una repo didattica (anche un piccolo progetto tuo):
- Aggiungi 8 commit con piccole modifiche, in uno introduci di proposito un bug.
- Verifica che
HEADè “bad” e che il primo commit è “good”. - Esegui
git bisect start+bad+good. Lascia che Git ti porti ai commit. Per ogni commit prova manualmente. - Identifica il commit colpevole.
- Ripeti l’esercizio scrivendo uno script
check-bug.she usandogit bisect run.
Quando NON usare bisect
- Bug non riproducibile (modulo 1): bisect ha bisogno di test deterministico.
- Bug nuovo (mai esistita versione “good”).
- Commit storia “appiattita” o ribasata che ha rimosso la cronologia rilevante.
Errori frequenti del principiante
- Dimenticare
git bisect resetalla fine. Resti in stato “detached HEAD” e confondi i prossimi push. - Usare bisect con bug flaky. I “false good” portano fuori strada. Stabilizza prima.
- Marcare bad/good a memoria. Verifica sempre, anche se sembra “ovvio”.
- Saltare lo script automatico. Un’ora di scripting risparmia tre ore di click.