Git bisect mi ušetřil hodiny debugování
Pátek odpoledne, testy padají, nikdo neví proč. Poslední týden proběhlo 50 commitů od různých lidí. Kdo to rozbil?
Dřív bych checkoutoval commit po commitu a testoval. S git bisect to najdu za 7 kroků místo 50. Binární vyhledávání - půlím historii, dokud nenajdu viníka.
Kdy to používám
Hlavně na regrese - něco fungovalo a přestalo. Typicky:
- Testy padají a "včera to šlo"
- Výkon se zhoršil
- Něco se chová jinak než dřív
Nehodí se když bug byl vždycky, nebo se projevuje náhodně (flaky testy).
Jak to používám v praxi
Celý postup je jednoduchý. Řeknu gitu kde je problém a kde byl naposledy klid:
git bisect start
git bisect bad # aktuální stav je rozbitý
git bisect good v1.0.0 # tady to ještě fungovalo
Git mě hodí doprostřed historie:
Bisecting: 25 revisions left to test after this (roughly 5 steps)
[def5678] Fix: Update user validation logic
Teď spustím testy a řeknu výsledek:
git bisect good # testy prošly
git bisect bad # testy padly
Opakuju, dokud git nenajde viníka:
def5678 is the first bad commit
Author: Jan Novak <jan@example.com>
Fix: Update user validation logic
A pak se podívám co se změnilo a ukončím session:
git show def5678 # co je v tom commitu
git diff def5678~1 def5678 # detailní změny
git bisect reset # zpět na původní větev
Automatizace - to je ta pravá síla
Ručně označovat good/bad je otrava. Proto skoro vždy používám git bisect run:
git bisect start HEAD v1.0.0
git bisect run npm test
Git sám spouští testy a podle exit code pozná jestli je commit dobrý (0) nebo špatný (1-127). Exit code 125 znamená "přeskoč" - třeba když se nedá buildit.
Vlastní testovací skript
Když potřebuju něco složitějšího, napíšu si skript:
#!/bin/bash
# test-bug.sh
# Instalace závislostí (potřeba po checkout)
npm install --silent 2>/dev/null
# Build projektu
npm run build --silent 2>/dev/null
# Specifický test pro bug
npm test -- --grep "user validation" --silent
# Exit code určí good/bad
exit $?
Spuštění:
chmod +x test-bug.sh
git bisect start HEAD v1.0.0
git bisect run ./test-bug.sh
Na co jsem narazil
Build nefunguje na starých commitech - stává se. Prostě vrátím 125 a git to přeskočí:
#!/bin/bash
npm run build || exit 125
npm test
Závislosti se změnily - čistá instalace řeší:
#!/bin/bash
rm -rf node_modules
npm ci --silent
npm test
Různé Node verze - nvm zachrání:
#!/bin/bash
source ~/.nvm/nvm.sh
nvm use 2>/dev/null || nvm use default
npm test
Bisect + diff = debug combo
Najít commit je půlka práce. Teď potřebuju zjistit CO přesně se pokazilo.
Rozebírám commit
# Zobrazení commitu
git show def5678
# Zobrazení pouze změněných souborů
git show --stat def5678
# Detailní diff s kontextem
git show -p def5678
# Diff s více kontextu (10 řádků kolem změny)
git show -p -U10 def5678
Srovnám s předchozím stavem
git diff def5678~1 def5678 # celý diff
git diff def5678~1 def5678 -- src/validators/user.ts # jen jeden soubor
git diff --word-diff def5678~1 def5678 # po slovech
Koukám do historie
git log --oneline --follow -- src/validators/user.ts # kdo měnil soubor
git log -p -- src/validators/user.ts # s diffem
git blame -L 50,60 src/validators/user.ts # kdo napsal tyto řádky
Pár triků navíc
Vlastní názvy místo good/bad
Někdy hledám kdy se něco ZLEPŠILO - třeba kdy se kód zrychlil. "Good" a "bad" pak nedávají smysl:
git bisect start --term-old=slow --term-new=fast
git bisect fast HEAD
git bisect slow v1.0.0
Uložení session
Když mě přeruší meeting, uložím si kde jsem:
git bisect log > bisect.log
# ...později...
git bisect replay bisect.log
Přeskakování commitů
Merge commity nebo rozbitý build? Skip:
git bisect skip # přeskoč tento
git bisect skip abc1234..def5678 # přeskoč rozsah
git bisect start --first-parent HEAD v1.0.0 # ignoruj merge commity
Vizualizace
Chci vidět co zbývá:
git bisect visualize # otevře gitk
git bisect view --oneline # textově
Reálný případ: DPH výpočet se rozbil
Tenhle příklad je z praxe. E-shop, ceny s DPH nefungují. Minulý týden (v2.3.0) to šlo.
# Spustím bisect
git bisect start
git bisect bad HEAD
git bisect good v2.3.0
# Bisecting: 23 revisions left to test (roughly 5 steps)
# Napíšu si testovací skript
cat > test-vat.sh << 'EOF'
#!/bin/bash
npm install --silent 2>/dev/null || exit 125
npm run build --silent 2>/dev/null || exit 125
# Test: cena 100 Kč s 21% DPH = 121 Kč
result=$(node -e "
const { calculateVAT } = require('./dist/utils/price');
console.log(calculateVAT(100, 0.21));
")
if [ "$result" = "121" ]; then
exit 0 # good
else
exit 1 # bad
fi
EOF
chmod +x test-vat.sh
# Pustím to
git bisect run ./test-vat.sh
# Za 5 kroků mám výsledek:
# abc7890 is the first bad commit
# Author: Pavel Svoboda
# refactor: Simplify price calculations
# Podívám se co změnil
git show abc7890
git bisect reset
A problém byl jasný
Pomocí diff jsem viděl:
- return price * (1 + vatRate);
+ return price * vatRate; // Bug: chybí základ ceny
Jednoduchá oprava:
// Správně
return price * (1 + vatRate);
Sdílení s týmem
Někdy potřebuju poslat kolegovi "hele, tady je ten bug":
git diff abc7890~1 abc7890 > changes.diff # export do souboru
git diff abc7890~1 abc7890 | pbcopy # rovnou do schránky (Mac)
Diff pak hodím do Code Diff pro barevné zobrazení, nebo pošlu link na GitHub:
gh browse abc7890 # otevře commit na GitHubu
Co mi pomáhá
Malé commity - čím menší, tím přesnější bisect:
# Tohle je k ničemu:
git commit -m "Various fixes and features"
# Tohle je super:
git commit -m "fix(price): Correct VAT calculation formula"
Každý commit musí jít buildit - jinak bisect skáče přes půlku historie.
Tagy na releases - pak vždycky vím kde hledat "good" commit:
git tag -a v2.3.0 -m "Release 2.3.0"
Git blame na doplnění - když už vím který soubor, blame mi ukáže kdo a kdy:
git blame src/utils/price.ts
# abc7890 (Pavel Svoboda 2026-01-15) return price * vatRate;
Chyby na které jsem narazil
"You need to start by git bisect start" - jo, zapomněl jsem git bisect start.
"No known good revision" - musím označit aspoň jeden dobrý commit přes git bisect good.
Zaseknutí na merge commitu - skip, nebo restart s --first-parent:
git bisect skip
# nebo
git bisect reset && git bisect start --first-parent HEAD v1.0.0
Flaky testy - to je nejhorší. Řeším opakováním:
#!/bin/bash
for i in {1..3}; do
npm test && exit 0
done
exit 1
Když bisect nestačí
Někdy jdu jinou cestou:
Git log s grep - když vím co hledám:
git log -p -S "calculateVAT" --source --all # kdo měnil tuhle funkci
git log --grep="VAT" --oneline # commity zmiňující VAT
Reflog - když jsem něco ztratil:
git reflog # kde všude byl HEAD
git checkout HEAD@{5} # vrať mě 5 kroků zpět
Pickaxe - kdy se objevila/zmizela funkce:
git log -p -S "function calculateVAT" -- "*.ts"
Shrnutí
Git bisect mi ušetřil hodiny práce. Místo procházení 50 commitů najdu problém za 7 kroků. S automatizací přes git bisect run to běží samo.
Hlavní je mít malé commity a buildovatelnou historii. Tagy na releases pomáhají najít výchozí bod.
A až najdete viníka, diff ukáže přesně co se pokazilo.
Potřebujete vizuálně porovnat změny v kódu po nalezení problematického commitu? Vyzkoušejte náš Code Diff nástroj – podporuje 22 programovacích jazyků a funguje přímo v prohlížeči.
Vyzkoušejte PorovnejText.cz zdarma
Nejrychlejší český nástroj pro porovnání textů. Vše probíhá ve vašem prohlížeči, žádná registrace není potřeba.
Porovnat texty nyní →Související články
Git diff mi nestačí - kdy a proč používám online diff
Jako programátor pracuju s git diff denně. Ale někdy potřebuju rychle porovnat dva kousky kódu a nechce se mi kvůli tomu otvírat IDE. Kdy použít co.
Markdown a README - jak kontroluju změny
Píšete dokumentaci v Markdownu? Tady je jak porovnávám změny v README a dalších md souborech.
Jak automatizuju changelog z Git commitů
Ruční psaní release notes mě nebavilo. Tady je jak jsem to automatizoval pomocí Conventional Commits.