git bisect: cara menemukan commit yang merusak kode
git bisect menemukan commit tempat sebuah error muncul dengan pencarian biner di riwayat. Jalankan git bisect start, tandai commit yang rusak dengan git bisect bad dan commit yang masih benar dengan git bisect good <hash>, lalu periksa commit yang diusulkan sampai Git menunjuk pelakunya; di akhir jalankan git bisect reset.
git bisect mencari commit yang memasukkan bug dengan metode pencarian biner. Anda menentukan satu commit tempat bug masih ada dan satu commit tempat bug belum ada. Git lalu memindahkan Anda ke tengah rentang dan bertanya: «di sini berfungsi atau rusak?». Setiap jawaban memangkas separuh kandidat, sehingga dari 1000 commit pelakunya ketemu sekitar 10 kali pengecekan.
Ini sangat berguna ketika bug tidak jelas penyebabnya: tes gagal, performa turun, tampilan berantakan, tetapi diff tidak memberi petunjuk. Alih-alih membaca ratusan perubahan, Anda cukup mengajukan pertanyaan sederhana yang sama berulang kali.
Cara kerja pencarian biner di riwayat
Misalnya versi yang masih benar adalah v2.3 dan kondisi saat ini adalah main, dengan 200 commit di antaranya. Git mengambil commit di tengah dan mengeceknya. Jika di sana sudah rusak, error muncul di paruh pertama; jika tidak, error muncul di paruh kedua. Jumlah kandidat berkurang setengah pada setiap langkah: 200, 100, 50, 25, 13, 7, 4, 2, 1. Delapan pengecekan, bukan dua ratus.
Syarat utamanya: kondisi «rusak» harus bersifat monoton. Jika bug muncul, hilang, lalu muncul lagi, bisect memang akan menemukan salah satu titik peralihan, tetapi belum tentu titik yang Anda cari.
git bisect langkah demi langkah: mode manual
1. Tentukan commit yang baik dan yang rusak
Commit yang rusak biasanya HEAD saat ini. Commit yang baik adalah commit yang pasti berfungsi: tag rilis sebelumnya, atau commit dari seminggu lalu. Untuk mencarinya, gunakan git log --oneline, git tag, atau git log --since="2 weeks ago".
2. Mulai sesi
git bisect start
git bisect bad # commit saat ini rusak
git bisect good v2.3 # di rilis v2.3 semuanya berfungsi
Bisecting: 99 revisions left to test after this (roughly 7 steps)
[4f5e6d7c...] Perbarui dependensi frontend
Hal yang sama bisa ditulis dalam satu baris: git bisect start HEAD v2.3, yaitu commit yang rusak lebih dulu, lalu yang baik. Git langsung memindahkan direktori kerja ke commit di tengah (dalam kondisi detached HEAD).
3. Periksa dan tandai
Build proyeknya, jalankan tes, atau reproduksi bug secara manual. Lalu laporkan hasilnya:
git bisect good # di sini berfungsi
Bisecting: 49 revisions left to test after this (roughly 6 steps)
git bisect bad # di sini rusak
Bisecting: 24 revisions left to test after this (roughly 5 steps)
4. Dapatkan hasilnya
Saat tinggal satu kandidat, Git menampilkannya:
a1b2c3d4e5f6... is the first bad commit
commit a1b2c3d4e5f6...
Author: Ivan Petrov <ivan@example.com>
Date: Tue Sep 29 11:40:12 2026 +0300
Cache hasil perhitungan keranjang
src/cart.js | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
5. Akhiri sesi
git bisect reset
Perintah ini mengembalikan Anda ke cabang tempat Anda memulai. Jangan lupakan langkah ini: selama sesi belum ditutup, Anda masih berada di detached HEAD dan commit baru mudah hilang. Dengan git bisect reset HEAD Anda tetap berada di commit yang ditemukan, sedangkan git bisect reset <commit> membawa Anda ke commit yang Anda tentukan.
Pencarian otomatis: git bisect run
Jika pengecekan bisa dinyatakan dalam satu perintah, serahkan seluruh pekerjaan kepada Git. git bisect run menjalankan skrip di setiap langkah dan menandai commit berdasarkan kode keluarnya:
| Kode keluar | Arti |
|---|---|
| 0 | good — commit baik |
| 1–127, kecuali 125 | bad — commit rusak |
| 125 | skip — commit tidak bisa diperiksa, lewati |
| di atas 127 (atau <0) | hentikan bisect (misalnya skrip berhenti karena sinyal) |
Contoh penggunaan:
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
Untuk pengecekan yang rumit, buat skrip kecil. Penting untuk memisahkan «tidak bisa di-build» dari «bug muncul». Jika tidak, bisect akan menganggap build yang rusak sebagai bug yang dicari:
#!/bin/sh
# check.sh
npm ci --silent || exit 125 # dependensi gagal dipasang — lewati
npm run build || exit 125 # tidak bisa di-build — lewati
node scripts/check-cart-total.js # 0 — oke, 1 — bug
chmod +x check.sh
git bisect run ./check.sh
Simpan skrip di luar file yang dilacak atau di folder yang ada di setiap commit yang diperiksa. Bisect memindahkan direktori kerja, dan file yang baru ditambahkan akan hilang pada commit lama. Cara paling aman adalah menaruhnya di /tmp atau di folder lain di luar repositori.
Tes yang belum ada di commit lama
Situasi yang sering terjadi: Anda sudah menulis tes yang mereproduksi bug, tetapi file tes itu tidak ada di commit lama. Solusinya adalah menyalin tes tersebut ke luar repositori:
cp tests/test_regression.py /tmp/
git bisect run pytest /tmp/test_regression.py
git bisect skip: saat commit tidak bisa diperiksa
Terkadang commit di tengah tidak bisa di-build atau gagal karena alasan lain. Anda tidak boleh menandainya good atau bad, karena hasilnya akan keliru. Lewati saja:
git bisect skip
git bisect skip v2.4..v2.4.3 # lewati satu rentang
Git akan memilih commit tetangganya. Jika commit yang dilewati berada tepat di batas, di akhir Anda akan melihat daftar «kemungkinan pelaku», bukan satu saja. Dalam kasus itu, periksa diff-nya satu per satu.
Istilah sendiri sebagai pengganti good dan bad
Bisect tidak hanya dipakai untuk mencari bug. Misalnya, Anda ingin tahu commit mana yang membuat halaman termuat lebih cepat. Menyebut commit cepat sebagai «rusak» membingungkan, jadi tersedia istilah alternatif:
git bisect start --term-old=slow --term-new=fast
git bisect fast HEAD
git bisect slow v2.3
Sinonim bawaannya adalah old dan new: git bisect new, git bisect old. Aturannya hanya satu: keadaan «lama» harus berada pada commit yang lebih awal.
Log sesi: log, replay, visualize
git bisect log— menampilkan semua penandaan Anda. Simpan ke file jika sesinya panjang.git bisect replay file— mengulang sesi dari log. Salah pada langkah keenam? Simpan log, hapus baris yang keliru, jalankangit bisect reset, lalureplay.git bisect visualize(ataugit bisect view) — menampilkan kandidat yang tersisa; dengan--onelinehasilnya ditampilkan lewat git log.
git bisect log > /tmp/bisect.log
# perbaiki log
git bisect reset
git bisect replay /tmp/bisect.log
Bisect dan merge commit
Dalam riwayat dengan banyak merge, bisect bisa membawa Anda masuk ke dalam cabang yang sudah digabungkan, yaitu ke commit-commit yang dibuat sebelum cabang itu disinkronkan dengan main dan karena itu berada di basis yang berbeda. Jika Anda ingin lebih dulu mengetahui merge mana yang membawa bug, gunakan:
git bisect start --first-parent
Dengan opsi ini Git hanya menelusuri parent pertama dari merge commit, yaitu riwayat cabang utama. Setelah menemukan merge yang bersalah, Anda bisa menjalankan bisect kedua di dalam cabang tersebut.
Kesalahan yang sering terjadi
- Keliru menandai good dan bad. Hasilnya tidak berarti apa-apa. Pulihkan sesi lewat
git bisect logdanreplay, tanpa memulai dari awal. - Direktori kerja kotor. Perubahan yang belum di-commit menghalangi perpindahan antar-commit dan memengaruhi hasil pengecekan. Sebelum mulai, lakukan commit atau
git stash. - Artefak build belum dibersihkan. Cache lama atau
node_modulesdari commit lain memberi hasil yang keliru. Buat build yang bersih di dalam skrip. - Tes yang tidak stabil (flaky). Jika tes kadang gagal dengan sendirinya, bisect akan menandai commit yang acak. Jalankan pengecekan beberapa kali atau perbaiki tesnya dulu.
- Lupa reset. Anda masih berada di detached HEAD lalu mulai bekerja. Commit yang hilang bisa dicari lewat reflog.
Contoh: mencari regresi dari awal sampai akhir
Pengguna melaporkan bahwa total keranjang dihitung salah ketika ada diskon. Di rilis v2.3 hasilnya benar, di main tidak. Kita tulis pengecekan minimal lalu jalankan pencarian:
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 # simpan perubahan yang belum di-commit
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
Pencarian di antara seratus commit berjalan tanpa campur tangan Anda, sementara Anda bisa mengerjakan hal lain. Log yang disimpan berguna jika Anda perlu menunjukkan kepada rekan tim bagaimana pelakunya ditemukan.
Apa yang dilakukan setelah commit ditemukan
Setelah pelakunya ketemu, lihat seluruh commit itu: git show a1b2c3d. Commit kecil dengan pesan yang jelas biasanya langsung menunjukkan penyebabnya. Inilah salah satu alasan tim menghargai commit atomik: bisect hampir tidak berguna pada riwayat yang penuh commit «fix stuff» berukuran raksasa. Setelah itu ada dua pilihan: memperbaiki bug dengan commit baru, atau jika perubahannya memang keliru dan sudah dipublikasikan, membatalkannya dengan git revert a1b2c3d.
Ringkasan
git bisect mengubah pencarian regresi dari membaca ratusan diff menjadi beberapa jawaban «berfungsi / tidak berfungsi», dan dengan git bisect run menjadi satu perintah saja. Yang dibutuhkan hanya dua patokan, yaitu commit yang baik dan commit yang rusak, serta pengecekan yang bisa diulang. Membaca riwayat, bernavigasi di antara commit, dan mencari bug di dalamnya dibahas dengan praktik dalam kursus Git.
Pertanyaan umum
Berapa langkah yang dibutuhkan git bisect?
Kira-kira logaritma dua dari jumlah commit dalam rentang: sekitar 7 langkah untuk 100 commit dan sekitar 10 untuk 1000. Git sendiri menampilkan perkiraan jumlah langkahnya dengan tulisan roughly N steps.
Bisakah bisect dijalankan jika commit yang baik tidak diketahui?
Harus ada setidaknya satu. Pilih commit lama yang pasti benar atau tag rilis, lalu periksa sendiri. Langkah tambahan karena rentang yang lebar hampir tidak memakan waktu.
Apakah git bisect mengubah riwayat repositori?
Tidak. Ia hanya memindahkan direktori kerja di antara commit dan menyimpan penandaan di referensi sementara refs/bisect, yang dihapus saat git bisect reset.
Bisakah menandai beberapa commit sebagai good sekaligus?
Bisa. Perintah git bisect good menerima beberapa commit sekaligus, yang mempersempit rentang, terutama pada riwayat bercabang.
Apakah bisect hanya untuk mencari bug?
Tidak. Bisect bisa dipakai untuk menemukan titik perubahan apa pun: kapan sebuah file muncul, kapan build menjadi lebih cepat, atau kapan perilaku berubah. Untuk keperluan ini istilah old/new atau istilah sendiri lewat --term-old dan --term-new sangat membantu.
Topik ini dibahas mendalam dengan praktik di kursus “Git dari Nol hingga Pengembang Percaya Diri”.
Ke kursus