git bisect
Команда git bisect выполняет бинарный поиск по истории коммитов и находит коммит, который внёс ошибку. Включает автоматизацию с помощью run.
Команда git bisect помогает найти точный коммит, в котором была введена ошибка, выполняя бинарный поиск по истории. Вы указываете Git коммит, где код работал («хорошим»), и коммит, где он сломан («плохим»), а Git последовательно переключается на промежуточный коммит для тестирования, каждый раз сужая диапазон вдвое, пока не останется единственный виновник.
В этой главе рассказывается, как вручную запустить сеанс bisect, как читать прогресс, который Git выводит после каждого ответа, как автоматизировать весь поиск с помощью тестовой команды, как пропускать нетестируемые коммиты и как восстановиться, если вы допустили ошибку.
Определение
Почему бинарный поиск
Если ошибка появилась где-то в последних 1 000 коммитах, проверять их по одному было бы крайне утомительно. Бинарный поиск требует всего около десяти проверок, чтобы обнаружить виновника, поскольку каждый ответ сокращает оставшихся кандидатов вдвое — примерно log2(N) шагов для N коммитов. git bisect автоматизирует всё управление состоянием, и вам остаётся лишь отвечать на вопрос «работает ли здесь?»
Запуск сеанса bisect
Начните сеанс, затем отметьте текущее сломанное состояние и известный рабочий коммит из прошлого:
git bisect start
git bisect bad # the current commit is broken
git bisect good v1.4.0 # this tag was known to workGit переключается на коммит, находящийся примерно посередине между ними. Вы собираете и тестируете эту ревизию, затем сообщаете результат:
git bisect good # this commit works — bug is newer
# or
git bisect bad # this commit is broken — bug is here or olderПосле каждого ответа Git выводит, сколько коммитов ещё осталось в диапазоне, и переключается на следующий промежуточный коммит:
Bisecting: 7 revisions left to test after this (roughly 3 steps)
[a1b2c3d4...] Refactor the parserПовторяйте цикл тестирования и разметки, пока Git не объявит первый плохой коммит:
a1b2c3d4 is the first bad commit
commit a1b2c3d4...
Refactor the parserЧтение результатов с помощью git bisect log
В любой момент можно просмотреть ответы, которые вы дали до сих пор. Это также удобно для сохранения записи сеанса:
git bisect logЕсли вы подозреваете, что неправильно пометили коммит, сбросьте сеанс и воспроизведите исправленный лог вместо того, чтобы начинать заново:
git bisect log > bisect-run.txt # edit out the mistaken line
git bisect reset
git bisect replay bisect-run.txtЗавершение сеанса
Когда Git сообщит о виновнике, вернитесь к тому месту, откуда начали:
git bisect resetЭто восстанавливает HEAD на ветку, на которой вы находились до начала bisect.
Автоматизация с помощью git bisect run
Если тест можно выразить в виде скрипта или команды, которая завершается с кодом 0 для хорошего коммита и ненулевым кодом для плохого, Git выполнит весь поиск без вашего участия:
git bisect start HEAD v1.4.0
git bisect run npm testGit переключается на каждый промежуточный коммит, выполняет команду, интерпретирует код завершения и останавливается на первом проблемном коммите — ручная разметка не требуется.
Команда может быть любым исполняемым файлом: однострочником, shell-скриптом или бинарным файлом. Код завершения 0 означает хороший коммит, любой код от 1 до 127 (кроме 125) означает плохой. Специальный код 125 сообщает Git, что коммит не может быть протестирован, и эквивалентен выполнению git bisect skip — используйте его, когда сборка сама по себе сломана в данной ревизии:
#!/bin/sh
# test.sh — skip commits that don't even compile
make || exit 125
./run-the-failing-case # exits non-zero when the bug is presentgit bisect start HEAD v1.4.0
git bisect run ./test.shgit bisect run должна быть идемпотентной и самодостаточной. Если тест оставляет артефакты сборки или изменённые файлы, добавьте шаг очистки, чтобы следующее переключение начиналось с чистого состояния — иначе устаревший бинарный файл может сделать хороший коммит похожим на плохой.Пропуск нетестируемых коммитов
Иногда проверяемый коммит сломан по не связанной причине — он не компилируется или отсутствует зависимость — и вы действительно не можете сказать «хороший» или «плохой». Скажите Git пропустить его:
git bisect skipGit выберет соседний коммит и продолжит сужение диапазона. Если в определённой области пропущено слишком много коммитов, Git может сообщить о диапазоне кандидатов, а не об одном конкретном коммите.
Основные параметры
| Команда | Описание |
|---|---|
git bisect start | Начинает сеанс bisect. |
git bisect bad [<commit>] | Помечает коммит как сломанный (по умолчанию текущий). |
git bisect good [<commit>] | Помечает коммит как рабочий. |
git bisect skip | Пропускает коммит, который не может быть протестирован (например, не собирается). |
git bisect run <cmd> | Автоматизирует поиск, используя код завершения тестовой команды. |
git bisect log | Выводит данные о хороших/плохих ответах, данных до сих пор. |
git bisect replay <file> | Воспроизводит сохранённый лог bisect. |
git bisect reset | Завершает сеанс и восстанавливает исходный HEAD. |
Связанные команды
Когда bisect указывает на виновника, следующие команды помогут изучить его и принять меры:
- git show — просмотр точных изменений, внесённых плохим коммитом.
- git blame — определение коммита, который последним затронул конкретную строку.
- git log — просмотр истории, по которой выполнялся bisect.
- git revert — отмена плохого коммита без перезаписи истории.
- git checkout — как Git перемещает
HEAD, что bisect использует внутренне.