VietTechiesHIỂU CÔNG NGHỆ. MỞ GÓC NHÌN.
☰ Chuyên mục

Git bisect tìm ra lần đổi số phiên bản trong 10.928 phiên bản nhân Linux qua khoảng 14 bước; một lần kiểm tra sai có thể làm chệch hướng tìm lỗi

22/10/2026 · VietTechies · Biên tập

Thiết bị đầu cuối máy tính DEC VT100 đời cũ, hiển thị chữ màu xanh lá trên màn hình đơn sắc


Năm 2009, Christian Couder, một người đóng góp cho Git, đã trình diễn cách tìm kiếm trong 10.928 phiên bản nhân hệ điều hành (kernel) Linux với khoảng mười bốn bước tự động. Công cụ ông dùng là git bisect.

Trong bài viết cho Linux-Kongress, Couder dùng một phép kiểm tra minh họa đơn giản: tìm mẫu trong Makefile ở thư mục gốc để xác định lần thay đổi số phiên bản. Thay vì xem lần lượt hàng nghìn commit, tức các bản ghi thay đổi mã nguồn, công cụ dùng kết quả của từng lần kiểm tra để thu hẹp số phiên bản còn cần xét.

Để tìm một lỗi hồi quy — lỗi khiến phần mềm đang hoạt động đúng trở nên sai — trong một hệ thống mã nguồn lớn, lập trình viên có thể phải tìm qua hàng nghìn commit giữa hai bản phát hành ổn định. Khi một tính năng hỏng hoặc hiệu năng giảm, phương pháp chia đôi tự động hóa việc tìm kiếm bằng cách coi đồ thị commit của kho mã là một không gian có thứ tự, giới hạn bởi một trạng thái đã biết có lỗi và một phiên bản tổ tiên đã biết hoạt động đúng.

Tìm kiếm nhị phân trên đồ thị có hướng không chu trình

Trong kiến thức tin học cơ bản, tìm kiếm nhị phân làm việc trên một mảng đã sắp xếp. Nhưng lịch sử phát triển phần mềm không phải một mảng phẳng; đó là đồ thị có hướng không chu trình (DAG) gồm các commit, với những nhánh song song và các lần hợp nhất nhánh. Để chia đôi đúng phạm vi, Git tính xem những phiên bản nào nằm giữa hai mốc. Công cụ giữ lại các commit là tổ tiên của commit có lỗi, đồng thời loại bỏ các commit là tổ tiên của bất kỳ commit nào đã biết hoạt động đúng.

Git chọn một commit sao cho số ứng viên còn lại được chia đều nhất có thể trong giới hạn của đồ thị, rồi chuyển mã nguồn về phiên bản đó để kiểm tra. Cách tìm này giả định rằng hành vi đang xét chuyển nhất quán từ đúng sang lỗi trong phần lịch sử được tìm kiếm. Đánh dấu một phiên bản là hoạt động đúng sẽ loại phiên bản đó cùng các tổ tiên; đánh dấu là có lỗi sẽ giữ lại phiên bản đó cùng các tổ tiên còn trong phạm vi tìm kiếm. Trong ví dụ của Couder, Git báo cần khoảng mười bốn bước, với các kết quả liên tiếp cho biết còn 10.928, 5.480 rồi 2.740 phiên bản.

Lệnh git bisect run giúp tăng tốc quy trình bằng cách tự động hóa. Lập trình viên truyền vào một tập lệnh có quyền thực thi để kiểm tra hành vi cần xét. Git lần lượt chuyển mã nguồn về từng phiên bản ứng viên, chạy tập lệnh rồi đọc mã thoát của tiến trình:

Mã thoát bằng 0 biểu thị thành công, đánh dấu commit là hoạt động đúng. Mọi mã thoát từ 1 đến 127 — trừ 125, mã dành riêng cho việc bỏ qua — đều đánh dấu commit là có lỗi. Nếu xảy ra tình trạng bất thường, các mã thoát từ 128 đến 255 yêu cầu Git dừng ngay toàn bộ quá trình chia đôi. Nhưng quy ước này có một cái bẫy nguy hiểm: các trình thông dịch lệnh tuân theo chuẩn giao diện hệ điều hành khả chuyển (POSIX) trả về mã 127 khi không tìm thấy lệnh và mã 126 khi tệp không có quyền thực thi. Vì git bisect run coi cả hai mã này là dấu hiệu phiên bản có lỗi, chỉ một lỗi gõ trong lệnh kiểm tra hoặc thiếu quyền thực thi cũng khiến những commit vô can bị kết luận nhầm là đã làm hỏng phần mềm.

Điểm yếu của phép chia đôi và bài toán bỏ qua phiên bản

Về toán học, phương pháp chia đôi rất gọn gàng, nhưng lịch sử phát triển thực tế lại phức tạp. Các kho mã thường có những phiên bản trung gian không biên dịch được vì cảnh báo không liên quan từ trình biên dịch (compiler), thiếu thư viện phụ thuộc (dependency) hoặc lỗi cú pháp tạm thời. Khi không thể chạy phép kiểm tra, lập trình viên không thể kết luận đúng đắn rằng commit hoạt động đúng hay có lỗi.

Để xử lý những phiên bản không thể kiểm tra, Git cung cấp lệnh git bisect skip; tập lệnh kiểm tra có thể yêu cầu bỏ qua bằng cách trả về mã thoát 125. Khi một commit bị bỏ qua, thuật toán tìm kiếm của Git chọn một commit khác ở gần đó. Tuy nhiên, việc bỏ qua có một hệ quả toán học không thể tránh: nếu lỗi hồi quy thực sự xuất hiện trong một chuỗi commit bị bỏ qua, Git không thể xác định chính xác commit gây lỗi. Quy trình kết thúc với một danh sách nghi vấn thay vì một commit duy nhất; bất kỳ commit nào trong danh sách cũng có thể đã đưa lỗi vào.

Nguy hiểm hơn nữa là cách tái hiện lỗi không đáng tin cậy. Như tài liệu chính thức của dự án nhân Linux cảnh báo, chỉ một lần phân loại sai commit cũng khiến phần tìm kiếm còn lại đi chệch hoàn toàn. Khi truy tìm một lỗi liên quan đến thời điểm thực thi chỉ thỉnh thoảng xuất hiện, lập trình viên có thể đánh dấu nhầm commit có lỗi là hoạt động đúng, khiến commit gây lỗi bị loại khỏi phạm vi tìm kiếm còn lại. Hướng dẫn của dự án khuyên dành thêm thời gian kiểm tra nếu cách tái hiện lỗi không ổn định. Nếu phát hiện phân loại nhầm, Git cho phép sửa nhật ký chia đôi rồi chạy lại theo nhật ký đó.

Tìm ra commit gây lỗi chưa phải là gỡ lỗi xong

Tìm được commit đầu tiên có lỗi mang lại một điểm khởi đầu rất giá trị, nhưng không thay thế việc chẩn đoán nguyên nhân. Commit mà phép chia đôi chỉ ra cho biết những dòng mã nào đã thay đổi, chứ không cho biết vì sao chúng làm hỏng hệ thống. Theo khuyến nghị trong hướng dẫn của dự án nhân Linux, lập trình viên nên xác minh kết quả bằng cách thử hoàn tác commit đã xác định trên cây mã nguồn mới nhất. Nếu việc hoàn tác khôi phục hành vi đúng, kết quả chia đôi được xác nhận.

Thực hành tìm lỗi bằng cách chia đôi mang lại một số bài học thực tế cho các nhóm kỹ thuật:

Commit nhỏ, mỗi commit chỉ gồm một thay đổi trọn vẹn, giúp duy trì khả năng tìm lỗi bằng phép chia đôi. Khi một commit gộp nhiều thay đổi không liên quan, dù đã tìm ra commit gây lỗi, lập trình viên vẫn phải phân tích một lượng thay đổi mã nguồn rất lớn. Giữ mỗi commit tập trung vào một việc giúp giảm số thay đổi cần điều tra sau khi phép chia đôi xác định được commit nghi vấn.

Mọi commit trên nhánh chính đều phải biên dịch được. Các commit trung gian bị hỏng có thể buộc người tìm lỗi phải bỏ qua phiên bản, khiến kết quả không rõ ràng nếu những commit bị bỏ qua nằm gần ranh giới bắt đầu xuất hiện lỗi hồi quy.

Kiểm tra cách tái hiện lỗi trước khi tìm trong lịch sử. Phép chia đôi tự động phụ thuộc vào việc tập lệnh kiểm tra trả về mã thoát phân loại chính xác hành vi đang điều tra. Chạy phép kiểm tra ở hai mốc đã biết hoạt động đúng và có lỗi giúp xác nhận rằng phép kiểm tra phân biệt được hai phiên bản đó; với lỗi chỉ thỉnh thoảng xuất hiện, có thể cần kiểm tra nhiều lần trước khi phân loại các commit trung gian.

Bài liên quan

Đọc bằng ngôn ngữ khác: English

Nguồn