14 puan yazan GN⁺ 2025-11-04 | 2 yorum | WhatsApp'ta paylaş
  • İkili arama (binary search) kavramı yalnızca mülakat sorularında değil, gerçek geliştirme aracı olan Git içinde de kullanılır
  • Büyük ölçekli monorepo ortamlarında testler aniden başarısız olduğunda, yalnızca loglarla nedenin izini sürmek zorlaşabilir
  • Bir ekip arkadaşı, iyi commit ile kötü commit'i belirleyip git bisect ile otomatik arama yaparak hatanın başladığı sorunlu commit'i tam olarak buldu
  • Her adımda bir script çalıştırılıp test sonucuna göre commit'ler otomatik sınıflandırılır ve ilk kez başarısız olan commit tespit edilir
  • İkili arama ilkesini kullanan git bisect, büyük kod tabanlarında hata nedenini hızla izlemek için güçlü bir araçtır

Algoritma ve gerçek vaka

  • İkili arama (binary search) algoritması, basit bir mülakat sorusunun ötesinde, gerçek hata ayıklama araçlarında da temel ilke olarak çalışır
  • git bisect, “hatanın ilk kez eklendiği commit'i (first bad commit)” bulmak için ikili arama kullanan bir araç olarak kullanılabilir
    • Leetcode'daki “First Bad Version” problemiyle benzer bir mantıkla çalışır

Gerçek iş ortamındaki problem durumu

  • Büyük ölçekli monorepo kullanılan ortamlarda her gün yüzlerce hatta binlerce commit oluşur
  • Belirli bir test başarısızlığının nedenini yalnızca loglarla izlemek zordur
  • Başarısızlığın nedeni, uzak çağrı için gereken token'ı alan yapılandırma dosyasındaki bir string değişikliğiydi; bu değişiklik başka bir hesabı referans aldığı için test başarısız oldu
  • Bu değişiklik entegrasyon testlerini geçti, ancak gerçekte sorun yarattı; sayısız commit arasında bunun tam olarak ne zaman ortaya çıktığını bulmak zordu

git bisect ile problem çözümü

  • Başka bir ekipten bir çalışma arkadaşı, git bisect komutunu kullanarak sorunlu commit'i hızla tespit etti
    • İyi commit (good) ve kötü commit (bad) belirlendikten sonra araç otomatik olarak aradaki commit'leri checkout edip testleri çalıştırarak nedeni daralttı
    • Her test çalıştırması zaman aldı, ancak sonunda sorunu tam olarak ekleyen commit bulundu
    • İlgili commit geri alınınca tüm testler normale döndü

git bisect çalışma süreci

  • Örnek commit geçmişi
    • Commit 1: ilk commit (normal)
    • Commit 2: refactoring (normal)
    • Commit 3: hata eklendi (hata oluşuyor)
    • Commit 4~10: işlevsel olmayan değişiklikler (hata sürüyor)
  • Çalıştırma komutu örneği
    git bisect start  
    git bisect bad HEAD  
    git bisect good HEAD~9  
    git bisect run ./test_script.sh  
    
  • Test script'i (test_script.sh) başarı durumunda 0, başarısızlıkta ise normal olmayan bir kod döndürür
  • git bisect aradaki commit'leri otomatik olarak checkout eder ve test script'ini çalıştırır;
    testin başarısız olduğu noktayı temel alarak ilk kötü commit'i tespit eder
  • Çıktıda b982ed9373fe235fe61c74b15faf264bc7142398 commit'inin ilk hata commit'i olduğu doğrulanır

Sonuç

  • git bisect, ikili arama ilkesini kod geçmişi taramasına uygulayan pratik bir araçtır
  • Büyük depolarda veya karmaşık değişiklik geçmişlerinde bile hatanın eklendiği anı hızla izleyebilir
  • Test otomasyonu ile birleştirildiğinde, büyük kod tabanlarında da istikrarlı hata ayıklama mümkün olur

2 yorum

 
kandk 2025-11-04

Bu tür sorunlar yüzünden TBD (trunk-based development) kullanıyoruz.

 
GN⁺ 2025-11-04
Hacker News görüşleri
  • Eskiden test kapsamı bile olmayan ve soyutlamaları berbat, devasa bir kod tabanında çalışırken git bisect neredeyse işe yarayan tek araçtı
    Kod o kadar karmaşıktı ki hatayı mantıksal olarak izlemek imkânsızdı; bu yüzden sorunun hangi commit’te ortaya çıktığını bulmak çok daha kolaydı
    Ama yüksek kaliteli bir kod tabanında bisect’e pek ihtiyaç olmuyordu. Her bileşen bağımsız olarak test edilebiliyordu ve gözlemlenebilirlik (observability) de iyiydi, bu yüzden nereye bakmak gerektiği açıktı

    • git bisect’in asla gereksiz olmadığını düşünüyorum. Sadece hatayı bulmakla kalmıyor, o hatanın neden ortaya çıktığını da anlamayı sağlıyor
      Commit mesajlarının özenli olduğu projelerde bisect ile geçmiş commit’lerin bağlamı anlaşılabiliyor ve bu içerik hata düzeltme commit’ine yansıtılabiliyor. Bu döngü commit kültürünün kendisini de güçlendiriyor
    • Bir zamanlar bir OSS programında garip bir string’in girdiği bir hatayı bulmuştum. C koduydu ve nedeni ilklendirilmemiş bir değişkendi
      Doğrudan izlemek imkânsızdı ama bir bisect script’i yazıp yaklaşık 30 dakika çalıştırınca sorunlu commit’i tam olarak buldum
    • git bisect başlangıçta Linux kernel regression’larını bulmak için eklenmiş bir araçtı
      Donanım sürücüleri gibi test edilmesi zor durumlarda bile sıradan kullanıcılar kernel üzerinde bizzat bisect yapıp sorunlu commit’i tespit edebilir hâle geldi
      Eskiden geliştiricilerden e-postayla yardım istemek gerekirdi, ama artık kullanıcılar sorunu kendileri daraltabiliyor
    • Amaç sadece hatayı düzeltmekse bisect gerekmeyebilir. Fakat bazen hatanın ne zamandan beri var olduğunu bilmek gerekir
      Örneğin yanlış işlenmiş verinin kapsamını izlemek veya “bu bir hata mı, özellik mi?” sorusunu değerlendirmek için faydalıdır
    • Bazen de hatanın ne zaman düzeltildiğini bilmek gerekir
      Örneğin müşteri 6 yıl önceki bir sürümde sorun yaşıyorsa, 4 yıl önceki sürüme yükseltince çözülüp çözülmeyeceği kontrol edilebilir
      Ya da kod büyük ölçüde refactor edildiyse, hata düzeltmesinin bilinçli mi yoksa tesadüfi mi olduğu da anlaşılabilir
  • git bisect iyi çalıştığında harikadır, ama her hatayı bulamaz
    Bazı hatalarda belirtiler eklendikleri anda ortaya çıkmaz, daha sonra yapılan başka bir değişiklikle görünür hâle gelir
    Böyle durumlarda bisect’in varsayımı bozulur: yani iyi commit ile kötü commit arasında hata sadece bir kez ortaya çıkmış olmalıdır
    Test edilemeyen commit’ler skip ile geçilebilir, ama sorunlu commit onlardan biriyse sonuç belirsizleşir

  • Yakın zamanda ilk kez ciddi şekilde git bisect kullandım ve neredeyse sihir gibi geldi
    Aynı ada sahip iki fonksiyon vardı ve kod formatlama çalışması sırasında doğru fonksiyonun import’u kaldırıldığı için sorun ortaya çıkmıştı
    Kodu defalarca inceledim ama bisect ile sorunlu commit’i bulana kadar nedenini hiç anlayamadım

  • Genelde hatanın hangi dosyada ya da fonksiyonda olduğunu zaten bildiğim için bisect’i çok sık kullanmıyorum
    Bunun yerine belirli bir fonksiyonun değişim geçmişini izlemek için git log -L :func_name:path/to/file.c komutunu kullanıyorum
    Bunun için .gitattributes ayarı gerekiyor

    • .gitattributes ayarıyla ilgili ne gerektiğini merak eden bir soru vardı; daha fazla ayrıntı isteniyordu
    • Her gün bisect kullandığını söyleyen biri de vardı. İş akışı tamamen farklı
    • C++ gibi çok biçimli fonksiyonlar içeren durumlarda git log -L zayıf kalıyor. Aynı isimli overload edilmiş fonksiyonlar arasında belirli bir sürümü izlemek zor olduğu için
    • .gitattributes yoksa git log -S ile belirli bir string’i içeren commit’leri bulmak da bir yöntemdir
  • Test script’lerinde exit code 125’i bilmek faydalıdır
    Build hatası gibi test sonucunun belirlenemediği durumlarda 125 döndürülürse bisect o commit’i atlar
    Bununla ilgili ayrıntıları blog yazımda derledim

    • Merge commit’lerinin CI geçen noktaları temsil ettiği depolarda git bisect --first-parent kullanmak faydalı olabilir
      Böylece “hatayı hangi PR ekledi?” sorusuna hızlıca ulaşılabilir; ardından ilgili branch üzerinde bir ayrıntılı bisect daha yapılabilir
  • Flaky test ortaya çıktığında bisect gerçekten parlıyor
    Race condition yüzünden emin olmak için testi yüz binlerce kez çalıştırmak gerekiyorsa, bisect script’ini arka planda bırakmak bunu pratik olarak çözülebilir kılar

    • Böyle durumlarda Bayesyen ikili arama uygulanırsa test sayısını çok ciddi biçimde azaltmak mümkün olabilir gibi görünüyor
  • Yakın zamanda Svelte ile yapılmış bir müzik çalar projesinde (lets-make-sweet-music.com) bisect ile bir hatanın kök nedenini buldum
    Ne test vardı ne de hata log’u, ayrıca dependabot güncellemeleri commit sayısını artırdığı için iz sürmek zordu
    Bisect sayesinde sorunlu commit’i buldum; neden de değiştirdiğim dosyanın çoklu event binding özelliğini uygulamıyor olmasıydı
    Commit’leri küçük tutarsanız, bisect ile bulunan sorunun nedenini hızla daraltabilirsiniz

  • Birisi “mülakatlarda binary search öğrenmenin dayatılması saçma” demişti; ama git bisect bu kavramın gerçek hayattaki iyi bir örneği
    Yine de bunu elle uygulamaya gerek yok. Çoğu dilde zaten standart kütüphanede bulunuyor

    • İlginç şekilde, binary search ilk kez 1940’larda önerilmiş olsa da hatasız bir uygulama ancak 1960’larda ortaya çıkmış diye bir anlatı var
      Orta indeksi hesaplarken (low + high) / 2 kullanılırsa overflow oluşabilir
    • Kişisel olarak her geliştiricinin en az bir kez keyfi hassasiyetli tamsayı dilinde (ör. Python) binary search’ü bizzat uygulamasının iyi olduğunu düşünüyorum
      Bu, invariant temelli düşünmeyi çalıştırmak için en iyi egzersizlerden biridir
  • Git’te bisect dışında da log -L, log -S, blame gibi harika kod keşif araçları var
    Bir zamanlar bu konuda bir blog yazısı yazmıştım