git bisect: kodu bozan commit nasıl bulunur
git bisect, hatanın ortaya çıktığı commit'i geçmişte ikili aramayla bulur. git bisect start çalıştırın, hatalı commit'i git bisect bad, kesin çalışan commit'i git bisect good <hash> ile işaretleyin, ardından Git suçluyu söyleyene kadar önerilen commit'leri kontrol edin; sonunda git bisect reset.
git bisect, hatayı getiren commit'i ikili arama (binary search) yöntemiyle bulur. Hatanın olduğu bir commit'i ve olmadığı bir commit'i belirtirsiniz — Git sizi aralığın ortasına geçirir ve sorar: «burası iyi mi, kötü mü?». Her cevap adayların yarısını eler, bu yüzden 1000 commit arasından suçlu yaklaşık 10 kontrolde bulunur.
Bu, özellikle hata belirgin olmadığında çok değerlidir: bir test kırıldı, performans düştü, arayüz kaydı ama diff'lerden hiçbir şey anlaşılmıyor. Yüzlerce değişikliği okumak yerine aynı basit soruyu birkaç kez sorarsınız.
Geçmişte ikili arama nasıl çalışır
Çalışan v2.3 sürümü ile mevcut main arasında 200 commit olduğunu varsayalım. Git ortadaki commit'i alır ve kontrol eder. Orada zaten bozuksa hata ilk yarıda ortaya çıkmıştır, değilse ikinci yarıda. Aday sayısı her adımda yarıya iner: 200, 100, 50, 25, 13, 7, 4, 2, 1. İki yüz yerine sekiz kontrol.
Buradan temel gereksinim çıkar: «bozuk» olma özelliği monoton olmalıdır. Hata ortaya çıktı, kayboldu ve tekrar ortaya çıktıysa, bisect geçişlerden birini bulur ama ihtiyacınız olanı bulmayabilir.
Adım adım git bisect: manuel mod
1. İyi ve kötü commit'leri belirleyin
Kötü olan genellikle mevcut HEAD'dir. İyi olan, her şeyin kesinlikle çalıştığı herhangi bir commit'tir: önceki sürümün tag'i, bir hafta önceki bir commit. Aday bulmak için git log --oneline, git tag veya git log --since="2 weeks ago" işinize yarar.
2. Oturumu başlatın
git bisect start
git bisect bad # mevcut commit bozuk
git bisect good v2.3 # v2.3 sürümünde her şey çalışıyordu
Bisecting: 99 revisions left to test after this (roughly 7 steps)
[4f5e6d7c...] Frontend bağımlılıklarını güncelle
Aynısı tek satırda da yazılabilir: git bisect start HEAD v2.3 — önce kötü, sonra iyi. Git çalışma dizinini hemen ortadaki commit'e geçirir (detached HEAD durumunda).
3. Kontrol edin ve işaretleyin
Projeyi derleyin, testi çalıştırın veya hatayı elle yeniden üretin. Ardından sonucu bildirin:
git bisect good # burada çalışıyor
Bisecting: 49 revisions left to test after this (roughly 6 steps)
git bisect bad # burada bozuk
Bisecting: 24 revisions left to test after this (roughly 5 steps)
4. Sonucu alın
Tek aday kaldığında Git onu gösterir:
a1b2c3d4e5f6... is the first bad commit
commit a1b2c3d4e5f6...
Author: Ahmet Yılmaz <ahmet@example.com>
Date: Tue Sep 29 11:40:12 2026 +0300
Sepet hesaplamasının sonucunu önbelleğe al
src/cart.js | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
5. Oturumu kapatın
git bisect reset
Komut sizi başladığınız branch'e geri döndürür. Bu adımı unutmayın: oturum kapanmadıkça detached HEAD'de kalırsınız ve yeni commit'leri kaybetmek kolaydır. git bisect reset HEAD sizi bulunan commit'te bırakır, git bisect reset <commit> ise belirttiğiniz herhangi bir commit'te.
Otomatik arama: git bisect run
Kontrol bir komutla ifade edilebiliyorsa bütün işi Git'e bırakın. git bisect run her adımda bir script çalıştırır ve işareti çıkış koduna göre kendisi koyar:
| Çıkış kodu | Anlamı |
|---|---|
| 0 | good — commit iyi |
| 1–127, 125 hariç | bad — commit kötü |
| 125 | skip — commit kontrol edilemiyor, atla |
| 127'den büyük (veya <0) | bisect'i durdur (örneğin script bir sinyalle çöktü) |
Çalıştırma örnekleri:
git bisect start HEAD v2.3
git bisect run npm test
git bisect run pytest tests/test_cart.py -x
git bisect run make check
Karmaşık kontroller için küçük bir script yazın. «Derlenmedi» ile «hata yeniden üretildi» durumlarını ayırmak önemlidir, yoksa bisect bozuk bir build'i aranan hata sanar:
#!/bin/sh
# check.sh
npm ci --silent || exit 125 # bağımlılıklar kurulamadı — atla
npm run build || exit 125 # derlenmedi — atla
node scripts/check-cart-total.js # 0 — tamam, 1 — hata
chmod +x check.sh
git bisect run ./check.sh
Script'i izlenen dosyaların dışında veya kontrol edilen tüm commit'lerde bulunan bir klasörde tutun: bisect çalışma dizinini değiştirir ve yakın zamanda eklenmiş bir dosya eski commit'lerde kaybolur. En güvenlisi onu /tmp'ye veya repository dışındaki herhangi bir klasöre koymaktır.
Önceden var olmayan bir test
Sık rastlanan bir durum: hatayı yeniden üreten bir test yazdınız ama eski commit'lerde bu dosya yok. Çözüm yine repository dışındaki bir kopyadır:
cp tests/test_regression.py /tmp/
git bisect run pytest /tmp/test_regression.py
git bisect skip: commit kontrol edilemediğinde
Bazen ortadaki commit derlenmez veya başka bir nedenle çöker. Onu good ya da bad olarak işaretlemek sonucu bozar. Atlayın:
git bisect skip
git bisect skip v2.4..v2.4.3 # bir aralığı atla
Git komşu bir commit seçer. Atlanan commit'ler tam sınırda kalırsa, sonunda tek bir commit yerine «olası suçlular» listesi görürsünüz — o zaman diff'lerine elle bakın.
good ve bad yerine kendi terimleriniz
Bisect yalnızca hata aramaz. Örneğin sayfanın daha hızlı yüklenmeye başladığı commit'i bulmak istiyorsunuz. Hızlı commit'lere «kötü» demek kafa karıştırır, bu yüzden alternatif kelimeler vardır:
git bisect start --term-old=slow --term-new=fast
git bisect fast HEAD
git bisect slow v2.3
Yerleşik eş anlamlılar old ve new'dir: git bisect new, git bisect old. Tek kural: «eski» durum daha önceki commit'e ait olmalıdır.
Oturum günlüğü: log, replay, visualize
git bisect log— tüm işaretlerinizi yazdırır. Oturum uzunsa bir dosyaya kaydedin.git bisect replay dosya— oturumu günlükten tekrar oynatır. Altıncı adımda mı hata yaptınız? Günlüğü kaydedin, yanlış satırları silin,git bisect resetve ardındanreplayçalıştırın.git bisect visualize(veyagit bisect view) — kalan adayları gösterir;--onelineile onları git log üzerinden listeler.
git bisect log > /tmp/bisect.log
# günlüğü düzenle
git bisect reset
git bisect replay /tmp/bisect.log
Bisect ve merge commit'leri
Çok sayıda merge içeren bir geçmişte bisect sizi birleştirilmiş bir branch'in içine götürebilir — branch main ile senkronize edilmeden önce oluşturulmuş ve bu yüzden farklı bir taban üzerine kurulmuş commit'lere. Önce hatayı hangi merge'ün getirdiğini anlamak istiyorsanız şunu kullanın:
git bisect start --first-parent
Bu durumda Git yalnızca merge commit'lerinin ilk parent'larını, yani ana branch'in geçmişini izler. Suçlu merge bulunduktan sonra ilgili branch'in içinde ikinci bir bisect başlatabilirsiniz.
Sık yapılan hatalar
- good ve bad karıştırıldı. Sonuç anlamsız olur. Baştan başlamadan oturumu
git bisect logvereplayile kurtarın. - Temiz olmayan çalışma dizini. Commit edilmemiş değişiklikler commit'ler arası geçişi engeller ve kontrolü etkiler. Başlamadan önce commit yapın veya
git stashkullanın. - Temizlenmemiş build çıktıları. Eski bir önbellek veya başka bir commit'ten kalan
node_modulesyanlış sonuçlar verir. Script'te temiz bir build yapın. - Kararsız (flaky) test. Test bazen kendiliğinden başarısız oluyorsa bisect rastgele bir commit'i işaretler. Kontrolü birkaç kez çalıştırın veya aramadan önce testi düzeltin.
- reset unutuldu. Detached HEAD'de kaldınız ve çalışmaya başladınız. Kaybolan commit'leri bulmak için reflog yardımcı olur.
Örnek: bir regresyonu baştan sona bulmak
Kullanıcılar indirim uygulandığında sepet toplamının yanlış hesaplandığını bildirdi. v2.3 sürümünde her şey doğruydu, main'de değil. Minimal bir kontrol yazıp aramayı başlatıyoruz:
cat > /tmp/check.sh <<'SH'
#!/bin/sh
npm ci --silent || exit 125
node -e "const c=require('./src/cart'); process.exit(c.total([{price:100}], 0.1) === 90 ? 0 : 1)"
SH
chmod +x /tmp/check.sh
git stash # commit edilmemiş değişiklikleri kaldır
git bisect start HEAD v2.3
git bisect run /tmp/check.sh
...
a1b2c3d4e5f6... is the first bad commit
git bisect log > /tmp/cart-bisect.log
git bisect reset
git stash pop
Yüz commit'lik aramanın tamamı siz başka işlerle uğraşırken, sizin müdahaleniz olmadan tamamlanır. Kaydedilen günlük, suçlunun tam olarak nasıl bulunduğunu ekip arkadaşlarınıza göstermeniz gerektiğinde işe yarar.
Bulunan commit ile ne yapmalı
Suçlu bulunduğunda onu bütünüyle inceleyin: git show a1b2c3d. Anlaşılır mesajlı küçük bir commit nedeni hemen ele verir — ekiplerin atomik commit'lere değer vermesinin nedenlerinden biri budur: dev «fix stuff» commit'lerinden oluşan bir geçmişte bisect neredeyse işe yaramaz. Sonra iki yol vardır: hatayı yeni bir commit ile düzeltmek ya da değişiklik tamamen başarısızsa ve zaten yayınlandıysa onu git revert a1b2c3d ile geri almak.
Özet
git bisect, bir regresyonu aramayı yüzlerce diff okumaktan birkaç «çalışıyor / çalışmıyor» cevabına, git bisect run ile de tek bir komuta indirger. Yalnızca iki referans noktası — iyi ve kötü commit — ve tekrarlanabilir bir kontrol gerekir. Geçmişi okumak, commit'ler arasında gezinmek ve geçmişte hata aramak Git kursunda uygulamalı olarak ele alınıyor.
Sık sorulan sorular
git bisect kaç adım sürer?
Yaklaşık olarak aralıktaki commit sayısının log2'si kadar: 100 commit için 7 civarı, 1000 commit için 10 civarı adım. Git tahmini roughly N steps olarak kendisi gösterir.
İyi commit bilinmiyorsa bisect başlatılabilir mi?
En az bir tane gerekir. Kesinlikle eski bir commit'i veya bir sürüm tag'ini alın ve elle kontrol edin; geniş aralık yüzünden eklenen birkaç adımın neredeyse hiçbir maliyeti yoktur.
git bisect repository geçmişini değiştirir mi?
Hayır, yalnızca çalışma dizinini commit'ler arasında değiştirir ve işaretleri git bisect reset ile silinen refs/bisect adlı yardımcı referanslarda saklar.
Birden fazla iyi commit belirtilebilir mi?
Evet, git bisect good komutuna birkaç commit verilebilir; bu, özellikle dallanmış geçmişlerde aralığı daraltır.
Bisect yalnızca hata aramak için mi kullanılır?
Hayır, bir özelliğin değiştiği herhangi bir anı bulabilir: bir dosyanın ne zaman eklendiği, build'in ne zaman hızlandığı ya da davranışın ne zaman değiştiği. Bunun için old/new terimleri veya --term-old ve --term-new ile kendi terimleriniz kullanışlıdır.
Bu konu “Sıfırdan Güvenilir Geliştiriciye Git” kursunda uygulamalı olarak ayrıntılı işleniyor.
Kursa git