Git bisect-tel gyors debugolás hibás módosítás esetén.

A git bisect: Hogyan találjuk meg azt a rossz commitot, ami miatt összeomlott a funkció?

Ha már elég ideje fejlesztesz, biztosan volt olyan, hogy tegnap még minden működött, ma reggel pedig a legújabb változatban valami kritikus funkció szépen elromlott. A tesztelők panaszkodnak, a bug reportok szállnak be, és az egyetlen kérdés a fejedben: „Mikor és hol rontottuk el?” Ha a projekt története hosszú és a commitok száma nagy, a manuális keresés pokoli munka lehet. Itt jön a képbe a git bisect, a fejlesztő egyik leghatékonyabb debug eszköze.

Mi is az a git bisect?

A git bisect egy bináris keresést végrehajtó git parancs, aminek a célja, hogy a lehető leggyorsabban megtalálja azt a commitot, amely bevezette a hibát. A bináris keresés elvén működik: folyamatosan felezi a „gyanús” commit tartományt egy ismert jó és egy ismert rossz verzió között. A fejlesztőnek csak annyit kell tennie, hogy megmondja a gitének, hogy az adott commit állapota „jó” vagy „rossz”, és a git maga navigál a történelemben, kiszűrve a szükségtelen lépéseket.

Gondolj úgy rá, mint egy rendőrségi kihallgatásra, ahol te vagy a főnyomozó. Ismersz egy ártatlan személyt (egy régi, stabil commit) és van egy holttest (az aktuális, hibás kód). A git bisect segít szisztematikusan kikérdezni az összes gyanúsítottat (a köztes commitokat), míg meg nem találod a tettest.

Hogyan működik a gyakorlatban? Egy példa PHP backend hibával

Képzeld el, hogy van egy PHP alkalmazásod, amelyik egy felhasználói listát jelenít meg. A főoldaladon (index.php) egyszerűen kilistázod az adatbázisból a felhasználókat. A tegnapi napon még tökéletesen működött. Ma azonban, miután beolvasztottál pár feature branchet, a lista üres. A hibaüzenet nem sokat segít: csak annyit látunk, hogy a getUsers() függvény null-t ad vissza.

Első lépésként elindítjuk a bisect-et. Megkeresünk egy olyan commitot, ahol biztosan működött a funkció (pl. két héttel ezelőtt), és egyértelműen rossz az aktuális main ág.

# Elindítjuk a bisect sessiont
git bisect start

# Megjelöljük a jelenlegi állapotot, mint ROSSZ
git bisect bad HEAD

# Visszamegyünk egy korábbi, jó commitra, és megjelöljük jóként
git checkout fea8321
# Teszteljük, hogy itt tényleg jó-e (pl. futtatunk egy tesztet, megnézzük a böngészőt)
git bisect good

Most a git automatikusan kiválaszt egy commitot a két megjelölt pont között, és oda „checkout-ol”. Itt a feladatunk, hogy teszteljük a funkciót. A PHP backend esetében ez gyakran azt jelenti, hogy futtatunk egy egyszerű szkriptet, vagy megnézzük a böngészőben az eredményt.

Tegyük fel, a git épp a b54f21c commitnál van. Létrehozunk egy gyors tesztfájlt, vagy megnézzük a böngészőben a helyi szervert:

// egy gyors teszt a terminálban, vagy egy test.php fájl
require_once 'UserRepository.php';
$repo = new UserRepository();
$users = $repo->getUsers();
if (empty($users)) {
    echo "ROSSZ: A lista üres!\n";
    exit(1); // Kilépési kód 1 = rossz
} else {
    echo "JO: " . count($users) . " felhasználó betöltve.\n";
    exit(0); // Kilépési kód 0 = jó
}

Ha a lista üres, a commit ROSSZ:

git bisect bad

Ha működik, akkor pedig:

git bisect good

A git ezután tovább felezi az intervallumot, és új commitra ugrik. Ezt ismételgetjük, amíg a git ki nem jelzi, hogy megtalálta az első rossz commitot:

b54f21c is the first bad commit
commit b54f21c9876a5f4321e0b0d0f123456789abcde
Author: Kolléga János 
Date:   Thu May 12 14:22:01 2023 +0200

    refactor: Átírás UserRepository getUsers metódusa

 UserRepository.php | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

Ez az! Most már tudjuk, hogy a b54f21c commitban történt refaktorálás okozta a problémát. Már nem 100 commitot kell vizsgálni, hanem egyetlen diff-et. A hiba okát is sokkal könnyebb megállapítani, hiszen csak azon a commiton belüli változásokat kell elemezni.

Frontend buktató: jQuery és Bootstrap függőségek

A git bisect nem csak backend hibákra használható. Képzelj el egy frontend bugot, ahol egy jQuery-es modal (Bootstrap segítségével) hirtelen nem jelenik meg. A commit history tele van CSS/SCSS frissítésekkel és JavaScript módosításokkal.

Amikor a bisect egy adott commitra ugrik, nem elég csak a backendet tesztelni. Meg kell nyitni a böngészőt, és manuálisan kattintani a gombra, amelyik a modalt megnyitja. Ha nem jelenik meg, akkor a commit rossz.

Itt egy tipikus helyzet, amikor egy rossz commit egy SCSS változtatást tartalmaz, ami törölte a modal display tulajdonságát:

// HIBÁS commitban szereplő SCSS változás
.modal {
    // display: block; // Ezt a sort véletlenül kommentelték ki
    position: fixed;
    z-index: 1050;
}

A frontend tesztelése manuális lépés, de létrehozhatsz egyszerű automatizált tesztet is (például Puppeteerrel), amely kilépési kóddal jelzi a sikerességet.

Gyakori buktatók és tanácsok

1. Interaktív tesztelés: A legnagyobb kihívás, hogy gyorsan és megbízhatóan tudj tesztelni minden egyes commitot. Érdemes előre elkészíteni egy egyszerű szkriptet (akár shell, akár PHP), amely lefuttatja a kritikus funkcionalitás tesztjét.
2. Merge commitok: Ha a történeted tele van merge commitokkal, a bisect néha „átugorhat” egyes változtatásokat. Ilyenkor a git bisect skip paranccsal át lehet lépni olyan commitokon, amelyeket nem lehet megfelelően tesztelni (pl. nem fordul le a kód).
3. Nem determinisztikus bugok: Ha a hiba nem mindig jelenik meg (pl. race condition), a bisect használata nehézkes. Ilyenkor sokszor kell tesztelni ugyanazt a commitot, ami elveszíti a módszer sebességének előnyét.
4. Megállj és gondolkodj: Amikor megtalálod az első rossz commitot, ne egyből kezdj el javítani. Először vizsgáld meg a diff-et (git show ) és értsd meg, *miért* okozta a változás a problémát. Gyakran a hiba oka komplexebb, mint amit elsőre látunk.

Összegzés

A git bisect egy olyan fejlesztői superpower, amit érdemes a szerszámtáradba tenni. Megváltoztatja a debugolás mentalitásodat: nem a „hol lehet a hiba a kódomban?” kérdéssel indulsz, hanem a „mikor került be a hiba a történetünkbe?” kérdéssel. Ez egy rendkívül hatékony szűrő, amely percek alatt leszűkíti a keresési területet néhány releváns sorra.

Legközelebb, amikor szembesülsz egy olyan hibával, ami „még tegnap még jó volt”, ne kezdj el kétségbeesetten böngészni a kódot. Indíts egy git bisect sessiont, kérdezd ki a commit történelmet, és hagyd, hogy a gited vezessen a bűnös változtatáshoz. A legtöbb esetben meg fogsz lepődni, milyen gyorsan a célhoz érkezel.