#howto - Guida all'utilizzo di git, parte 10: bisect

Scritto da il
Redatto da
bash
git

← Articolo precedente, parte 9: studiare la storia delle modifiche.
→ Articolo successivo, parte 11: GUI

Quando si parla di software di versioning, git è sicuramente il primo programma che ci viene in mente. Rappresenta l’alternativa più diffusa a sistemi come svn, utilizzata anche in ambito enterprise.

Rappresenta anche uno dei primi scogli che dipendenti alle prime armi affrontano in azienda.

Ecco quindi una guida passo passo a git, parte 10: bisect.

Obiettivi

Questo articolo affronterà i seguenti argomenti:

  • bisect

Bisect

Bisect è un comando tanto complesso quanto affascinante: utilizza la ricerca binaria per cercare il commit che, presumibilmente, ha generato un bug.

È un metodo “lento” e non molto ragionato di ricerca, infatti non si basa sullo studio del codice ma tanto sul testare poco a poco i vari commit in un determinato range, fino a trovare quello che può aver dato problemi.

Bisect start

Innanzitutto identificare tramite git log il range di commit incriminato, identificato da un bad commit (ovvero un commit dove si presenta il problema) e un good commit (ovvero un commit il problema non era presente). Questo passaggio rende chiara una cosa: non ha senso usare questo metodo se il range di commit è troppo piccolo (1 o 2 commit per intenderci), in quel caso è consigliato fare lo switch manuale ai due commit.

Una volta identificati i due commit (e copiati i due SHA) si può scrivere:

git bisect start
git bisect good SHACOMMIT_BUONO
git bisect bad SHACOMMIT_CATTIVO

A questo punto git farà automaticamente checkout ad un commit che sta in mezzo al range.

Ripercorrere l’albero step by step

Si parte quindi da metà percorso e, piano piano, si indica a git quali commit hanno il bug.

Se nel commit attuale il bug è presente scrivere:

git bisect bad

Se non è presente scrivere:

git bisect good

La ricerca procederà dividendo a metà il range di commit in cui il bug è presente, fino ad individuare il colpevole.

Attenzione:

limitarsi a cercare il bug di partenza, essendo che si parla di commmit precedenti, alcune feature magari non saranno presenti, quindi si potrebbero presentare ulteriori bug a causa del fatto che mancano dei commit.

Bug trovato

Quando il bug viene fuori esce la scritta is the first bad commit preceduto dal codice SHA del bug e subito dopo il relativo log del bug.
A questo punto si può annullare il bisect:

git bisect reset

Quindi si può prendere una decisione relativa al commit, ad esempio eliminarlo tramite revert:

git revert SHACOMMIT

Ovviamente la soluzione dipende dal caso specifico e non può essere trattata in modo generale. Sicuramente il primo passo è discuterne con l’autore delle modifiche (se non si è autore di quella modifica ovviamente).

Esempio e test

Forse in questo caso può essere utile costruirsi un caso di test. Creiamo da zero un progetto git:

mkdir testbisect 
cd testbisect
git init

Quindi creiamo un file:

touch file.txt

Faremo quindi una linea per commit, ad un certo punto introdurremo il bug:

echo "Riga 1">> file.txt
git add .
git commit -m "primo commit" 

echo "Riga 2">> file.txt
git add .
git commit -m "commit numero 2" 

echo "Riga 3">> file.txt
git add .
git commit -m "commit numero 3" 

echo "Riga 4">> file.txt
git add .
git commit -m "commit numero 4" 

# Introduciamo qui il bug usando sed
sed -i '2s/2/3/' file.txt
sed -i '3s/3/2/' file.txt

git add .
git commit -m "commit numero 5 CON BUG" 

echo "Riga 5">> file.txt
git add .
git commit -m "commit numero 6" 

echo "Riga 6">> file.txt
git add .
git commit -m "commit numero 7" 

A questo punto dovremmo avere una situazione del genere:

commit af2e2ffea47045f755f3f10680ff93330d425f93 (HEAD -> main)
Author: PsykeDady <[email protected]>
Date:   Thu May 1 20:55:38 2024 +0200

    commit numero 7

commit fd9b4584bc3bb1d0544dde98f6395ab0d8690fac
Author: PsykeDady <[email protected]>
Date:   Thu May 1 20:55:38 2024 +0200

    commit numero 6

commit 4303a5ac4c5a04ab4462b64fd7840bae21d3c041
Author: PsykeDady <[email protected]>
Date:   Thu May 1 20:55:38 2024 +0200

    commit numero 5 CON BUG

commit 6a45d1e400f8b8bf5f725705a7e0217e11d89b31
Author: PsykeDady <[email protected]>
Date:   Thu May 1 20:55:38 2024 +0200

    commit numero 4

commit 7d8a5d0fdf42978a7ba60cc9e53478b9058eb3d8
Author: PsykeDady <[email protected]>
Date:   Thu May 1 20:55:38 2024 +0200

    commit numero 3

commit d21417cb4418bcc2430f759ce911ace20882a585
Author: PsykeDady <[email protected]>
Date:   Thu May 1 20:55:38 2024 +0200

    commit numero 2

commit 0a92514306305fc623026f49348118e0e5e0829c
Author: PsykeDady <[email protected]>
Date:   Thu May 1 20:55:38 2024 +0200

    primo commit

Ovviamente varieranno alcune informazioni come nome, data ma soprattutto i vari commit SHA.
Ora ci si deve mettere nell’ottica di non sapere quale commit ha portato il bug, inizia quindi la ricerca con il comando bisect. Prendiamo SHA del primo commit e del commmit finale:

git bisect start
git bisect good 0a92514306305fc623026f49348118e0e5e0829c
git bisect bad af2e2ffea47045f755f3f10680ff93330d425f93

A questo punto git farà checkout a metà tra di due branch, ovvero il branch numero 4. Nel nostro caso il bug ha scambiato riga due e tre, per vedere se è presente stampiamo quel file:

cat file.txt

Notando che la riga due precede la riga tre, possiamo supporre che il bug non sia presente. Marchiamo il commit come positivo:

git bisect good

git, per cercare il bug, passerà sui commit 5, 6 e 7. Nello specifico si fermerà sul commit 6 ovvero:

[main fd9b458] commit numero 6

Questo commit contiene il bug, infatti scrivendo:

cat file.txt

Si potranno notare righe 3 e 2 scambiate. Marchiamo il commit come negativo:

git bisect bad

Per lo stesso ragionamento, il nuovo commit (commit numero 5 CON BUG) è un altro commit negativo:

git bisect bad

A questo punto verrà stampato:

4303a5ac4c5a04ab4462b64fd7840bae21d3c041 is the first bad commit
commit 4303a5ac4c5a04ab4462b64fd7840bae21d3c041
Author: PsykeDady <[email protected]>
Date:   Thu May 1 20:55:38 2024 +0200

    commit numero 5 CON BUG

 file.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Abbiamo trovato il bug. Essendo un commit che introduce solo il bug e nient’altro si può fare revert:

git revert 4303a5ac4c5a04ab4462b64fd7840bae21d3c041
history_edu Revisioni