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'
git bisect startmemulai sesi bisect.git bisect badtanpa hash artinya commit yang sedang kamu pakai (HEAD) rusak.git bisect good v1.0artinya commit bertagv1.0masih bagus. Boleh juga pakai hash darigit log --oneline, misalnyagit bisect good 1a7c3e0.- Begitu tahu ujung bagus dan ujung rusak, Git langsung pindah (checkout) ke commit di tengah.
3 revisions left to test after this (roughly 2 steps)artinya setelah commit ini masih ada 3 commit yang mungkin perlu dites, kira-kira 2 tes lagi. - Kamu tes commit itu, lalu jawab
git bisect goodataugit bisect bad. Tiap jawaban membuang separuh kandidat, dan Git pindah ke tengah sisanya. 5f0c8a5 is the first bad commit: ketemu. Commit itulah yang pertama kali memasukkan bug. Dari pesannya, "pakai diskon member", kamu tahu bagian kode mana yang harus diperiksa.git bisect resetmengakhiri sesi dan membawa kamu kembali ke branch semula.
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
git bisect start HEAD v1.0sama denganstart, lalubaduntukHEAD, lalugood v1.0.git bisect run node test.jsmenjalankan tes di tiap commit yang di-checkout, lalu menandai sendiri: exit code0jadi good,125dilewati,1sampai127yang lain jadi bad.- Commit yang gak bisa dites sama sekali (misalnya gagal di-build) bisa dilewati dengan
git bisect skip. Git pindah ke commit lain di dekatnya.
⚠️ Jebakan yang sering ketemu
- Salah menandai satu commit. Bisect percaya penuh pada jawabanmu. Satu
goodyang harusnyabadbikin Git menunjuk commit yang salah, dan gak ada error yang muncul. Tes beneran setiap commit sebelum menjawab. - Lupa
git bisect reset. Kamu tertinggal di commit lama dalam keadaan detached HEAD. Commit baru yang kamu buat di situ gak masuk kemain. - Script tes ikut hilang. Kalau
test.jsbaru di-commit belakangan, commit lama gak punya file itu. Biarkan script tes di luar commit (untracked) selama bisect. - Di latihan, tesnya
sh cek.sh, bukannode test.js. Terminal latihan gak punya Node, jadicek.shmemeriksaapp.jsdan mencetakOKatauGAGAL. File itu gak di-commit, jadi tetap ada di tiap commit yang di-checkout, persis seperti saran di atas.
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.