Git Bisect — Git

Bug tiba-tiba muncul, tapi kamu tidak tahu commit mana penyebabnya. git bisect menemukannya dengan binary search — O(log n) bukan O(n). Intuisi: kalau ada…

git bisect mencari commit pertama yang bikin bug dengan cara membelah dua riwayat commit berulang kali. Kamu cukup kasih tahu dua hal: commit mana yang masih bagus dan commit mana yang sudah rusak. Mirip ngecek rekaman CCTV parkiran: jam 08.00 motormu masih ada, jam 16.00 sudah hilang. Kamu putar rekaman jam 12.00. Motornya masih ada? Berarti kejadiannya antara 12.00 dan 16.00, dan rekaman pagi gak perlu ditonton lagi.

🧪 Tebakan cepat: antara versi yang masih bagus dan versi yang rusak ada 1.024 commit. Kalau dicek satu per satu, bisa sampai 1.024 kali tes. Dengan bisect, paling banyak berapa kali tes: 10, 100, atau 512? Tebak dulu, jawabannya ada di bagian "Kenapa cepat sekali".

Kasusnya: total keranjang jadi salah

Sebuah toko online punya function total() di app.js. Di rilis v1.0, keranjang Rp50.000 + Rp100.000 totalnya Rp150.000. Sekarang, 8 commit kemudian, totalnya jadi Rp135.000 untuk pembeli biasa. Gak ada yang ingat commit mana penyebabnya. Lihat riwayatnya dulu dengan git log --oneline:

$ git log --oneline
c4b7f08 (HEAD -> main) tambah halaman kontak
3e2d9c7 perbarui README
8a6e1b6 tambah ikon keranjang
5f0c8a5 pakai diskon member
9d3b7e4 rapikan CSS keranjang
2c8f6d3 tambah tombol beli
7e1a5c2 perbaiki typo di footer
4b9d2f1 tambah halaman produk
1a7c3e0 (tag: v1.0) rilis v1.0

Commit paling atas (HEAD) rusak, commit paling bawah (v1.0) masih bagus. Di antaranya ada 8 kandidat: 7 commit yang belum dites, ditambah HEAD yang sudah pasti rusak. Untuk mengetes, ada file test.js yang mengecek totalnya: node test.js mencetak OK kalau benar, GAGAL kalau salah.

Langkah bisect

Ini sesi lengkapnya. Hash aslinya 40 karakter, di sini disingkat 7 karakter supaya muat.

$ git bisect start
$ git bisect bad              # HEAD sekarang rusak
$ git bisect good v1.0        # v1.0 masih bagus
Bisecting: 3 revisions left to test after this (roughly 2 steps)
[9d3b7e4] rapikan CSS keranjang
$ node test.js
OK: total 150000
$ git bisect good
Bisecting: 1 revision left to test after this (roughly 1 step)
[8a6e1b6] tambah ikon keranjang
$ node test.js
GAGAL: total 135000, harusnya 150000
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[5f0c8a5] pakai diskon member
$ node test.js
GAGAL: total 135000, harusnya 150000
$ git bisect bad
5f0c8a5 is the first bad commit
commit 5f0c8a5
Author: Bima <[email protected]>

    pakai diskon member
$ git bisect reset
Previous HEAD position was 5f0c8a5 pakai diskon member
Switched to branch 'main'

Selama bisect, HEAD menunjuk langsung ke sebuah commit lama, bukan ke branch. Keadaan ini disebut detached HEAD. Itu sebabnya git bisect reset wajib di akhir.

Kenapa cepat sekali

Tiap tes membuang separuh kandidat. Di contoh tadi: 8 kandidat jadi 4, lalu 2, lalu 1. Cuma 3 kali tes, padahal cek satu per satu bisa butuh 8 kali.

Kandidat Cek satu per satu, paling banyak Bisect, paling banyak
8 8 tes 3 tes
100 100 tes 7 tes
1.024 1.024 tes 10 tes
1.000.000 1.000.000 tes 20 tes

1.024 dibelah dua sepuluh kali: 512, 256, 128, 64, 32, 16, 8, 4, 2, 1. Jadi cuma sekitar 10 tes. Itu jawaban tebakannya. Caranya sama dengan binary search: kandidatnya dua kali lipat, tesnya cuma nambah satu.

💡 Biar Git yang mengetes: git bisect run

Kalau tesnya bisa jalan otomatis, Git bisa menandai sendiri. Syaratnya cuma satu: script-nya harus selesai dengan exit code 0 kalau bagus dan exit code lain kalau rusak.

// test.js: cek total keranjang pembeli biasa
const { total } = require('./app.js')
const hasil = total([50000, 100000], { member: false })
if (hasil === 150000) {
  console.log('OK: total 150000')
  process.exit(0) // 0 = good
}
console.log(`GAGAL: total ${hasil}, harusnya 150000`)
process.exit(1) // selain 0 = bad
$ git bisect start HEAD v1.0   # bad dan good sekaligus
$ git bisect run node test.js

⚠️ Jebakan yang sering ketemu

TL;DR: git bisect mencari commit pertama yang rusak dengan membelah dua riwayat. Urutannya: git bisect start, git bisect bad (HEAD rusak), git bisect good v1.0 (yang masih bagus), lalu tes tiap commit yang di-checkout dan jawab good atau bad sampai muncul is the first bad commit. Akhiri dengan git bisect reset. Tiap tes membuang separuh, jadi 1.024 commit cuma butuh sekitar 10 tes. git bisect run mengetes otomatis: exit code 0 berarti good.

Yang akan kamu pelajari