Sau Bài 7 học cách cứu commit tưởng đã mất, bài này giải quyết một bài
toán khác: commit nào trong 200 commit vừa qua đã làm hỏng tính năng X? Dò từng commit một
(build lại, test lại) là O(n) — chậm và nản. git bisect biến việc đó thành
một bài toán tìm kiếm nhị phân quen thuộc, giảm xuống còn O(log n) bước.
1. Bài Toán: Lỗi Nằm Ở Đâu Trong Hàng Trăm Commit?
Giả sử bạn biết commit hiện tại (HEAD) có lỗi, và commit từ 1 tuần trước (hoặc 1 tag
release cũ) thì chắc chắn ổn. Ở giữa 2 điểm đó là hàng chục, hàng trăm commit. Dò tuần tự từ đầu tới
cuối tốn tối đa n lần build+test. Nhưng nếu giả định lỗi chỉ xuất hiện
đúng 1 lần và không biến mất rồi quay lại (tính chất đơn điệu —
monotonic), bạn có thể áp dụng đúng thuật toán tìm kiếm nhị phân trên mảng đã sắp xếp: luôn kiểm tra
điểm giữa, rồi thu hẹp một nửa phạm vi mỗi lần.
2. git bisect start/good/bad: Thu Hẹp Phạm Vi
Quy trình thủ công gồm 4 loại lệnh:
| Lệnh | Ý nghĩa |
|---|---|
git bisect start |
Bắt đầu phiên bisect, chưa biết ranh giới good/bad nào. |
git bisect bad [ref] |
Đánh dấu 1 commit là lỗi (mặc định là HEAD hiện tại nếu không truyền ref). |
git bisect good <ref> |
Đánh dấu 1 commit cũ hơn là ổn — thiết lập ranh giới dưới của phạm vi tìm kiếm. |
git bisect reset |
Kết thúc phiên, quay lại đúng branch/HEAD ban đầu trước khi bisect. |
Ngay khi có cả 1 mốc good và 1 mốc bad, Git tự động
checkout commit ở chính giữa phạm vi đó — luôn dưới dạng
detached HEAD (Bài 3), vì bạn chỉ đang "ghé thăm" để test chứ không làm
việc trên đó. Bạn build/test commit đó, rồi báo lại good hoặc bad, Git tiếp
tục thu hẹp phạm vi còn một nửa. Lặp lại tới khi phạm vi chỉ còn đúng 1 commit — đó chính là "thủ
phạm" đầu tiên gây lỗi.
skip, đừng đoángit bisect skip báo cho Git biết "bỏ qua commit này, không tính là good hay bad" — Git
sẽ chọn 1 điểm giữa khác thay vì buộc bạn đoán mò, tránh làm sai lệch kết quả tìm kiếm.
3. Tự Động Hoá Với git bisect run
Thay vì tự tay test rồi gõ good/bad hàng chục lần,
git bisect run <lệnh> giao toàn bộ vòng lặp cho 1 script — thường là lệnh chạy
test. Git đọc mã thoát
(exit code) của lệnh đó để tự quyết định:
| Exit code | Git hiểu là |
|---|---|
0 |
good — commit này ổn. |
1–124, 126–127 |
bad — commit này lỗi. |
125 |
skip — không thể test commit này (dành riêng, không phải "bad"). |
Toàn bộ vòng lặp checkout → chạy script → đọc exit code → thu hẹp phạm vi diễn ra tự động, không cần tương tác — cực kỳ hữu ích khi phạm vi tìm kiếm lên tới hàng trăm commit.
bisect run nên tự lo phần buildgit bisect run npm test hoặc 1 script bash tự build rồi chạy test
cụ thể. Script nên exit 125 ngay khi build thất bại vì lý do không liên quan tới bug
đang tìm (ví dụ thiếu file tại thời điểm đó) — để Git bỏ qua commit đó thay vì tính nhầm là bad.
4. So Sánh Độ Phức Tạp: O(log n) vs O(n)
| Số commit cần dò | Dò tuần tự (tối đa) | git bisect (tối đa) |
|---|---|---|
| 16 | 16 lần | ~4 lần |
| 256 | 256 lần | ~8 lần |
| 1.000.000 | 1.000.000 lần | ~20 lần |
git bisect có thể hội tụ sai chỗ. Luôn
xác nhận thủ công commit mà Git chỉ ra thực sự là nguyên nhân trước khi kết luận.
git bisect start --first-parent
giới hạn việc tìm kiếm chỉ theo nhánh chính, bỏ qua nội dung bên trong các merge — hữu ích khi bug
chắc chắn nằm ở nhánh chính chứ không phải trong 1 feature branch đã merge vào.
Sân chơi tương tác: Demo Bisect Trên 24 Commit Giấu 1 Thủ Phạm
Bên dưới là 24 commit liên tiếp — đúng 1 commit trong số đó âm thầm gây lỗi (nội dung không hé lộ
trước, giống thực tế). Hãy tự tay bisect: đánh dấu 1 mốc cũ là good, HEAD hiện tại là bad, rồi lặp lại
good/bad theo commit Git tự checkout tới khi tìm ra thủ phạm. Thử cả git bisect run
để xem toàn bộ vòng lặp tự động hoá chỉ trong vài bước.
Terminal giả lập
git bisect startgit bisect bad [C<n>]git bisect good C<n>git bisect skipgit bisect run(tự động hoá)git bisect loggit bisect reset
Nhật ký
Trắc nghiệm ôn tập
Câu 1: Với 1000 commit giữa 1 mốc good và 1 mốc bad, git bisect cần tối đa khoảng bao
nhiêu lần checkout+test để tìm ra thủ phạm, so với dò tuần tự?
Trắc nghiệm ôn tập
Câu 2: Trong git bisect run <script>, mã thoát (exit code) 125 có ý
nghĩa gì?
Trắc nghiệm ôn tập
Câu 3: Điều gì khiến kết quả của git bisect có thể SAI (chỉ ra nhầm thủ phạm)?