Bisect - самый недооценённый инструмент Git. На истории в десятки тысяч коммитов он находит источник регрессии за 10-15 шагов.
Базовый ручной сценарий
git bisect start
git bisect bad # текущий - сломанный
git bisect good v1.4 # знаем, что v1.4 работал
Git переключит на средний коммит. Ты тестируешь, отвечаешь:
git bisect bad # баг есть
git bisect good # бага нет
Git делит интервал пополам и переключает дальше. После
log2(N) ответов:
a1b2c3d is the first bad commit
commit a1b2c3d
Author: ...
Date: ...
refactor: extract calculator class
По окончании:
git bisect reset # вернуть HEAD на ветку, с которой начинали
Автоматический режим: bisect run
Если есть скрипт-проверяльщик - Git делает всё сам.
git bisect start
git bisect bad
git bisect good v1.4
git bisect run ./check.sh
Контракт скрипта:
exit 0- коммит good (тест прошёл)exit 1..124, 126..127- коммит bad (тест упал)exit 125- пропустить коммит (не удалось проверить)- другие коды - фатальная ошибка, bisect остановится
Pytest и большинство тестовых фреймворков подходят напрямую (возвращают 0/1):
git bisect run pytest tests/test_login.py::test_password_reset
Полезные команды во время bisect
git bisect log # лог сессии bisect
git bisect visualize # показать оставшийся интервал коммитов
git bisect skip # пропустить текущий (не собирается / нерелевантный)
git bisect reset # выйти и вернуться на исходную ветку
git bisect replay <log> # повторить сессию из сохранённого лога
Произвольные термины
Если «good/bad» не подходит (ищешь когда фича появилась):
git bisect start --term-old=missing --term-new=present
git bisect present
git bisect missing v1.0
Подводные камни
- Промежуточные коммиты не собираются. Bisect требует, чтобы
каждый шаг можно было проверить. Если коммиты атомарны (см.
atomic-commit) - всё ок. Если в истории мусор -
bisect skipилиexit 125в скрипте. - Перемежающаяся регрессия. Если баг возник, исчез, возник снова
- bisect найдёт какую-то границу, но не первую. Лечится точностью теста.
- Внешние зависимости. Если результат зависит от версии пакета, обнови зависимости в скрипте перед тестом - иначе bisect ловит окружение, а не коммит.