W3docs

git bisect

Команда git bisect выполняет бинарный поиск по истории коммитов и находит коммит, который внёс ошибку. Включает автоматизацию с помощью run.

Команда git bisect помогает найти точный коммит, в котором была введена ошибка, выполняя бинарный поиск по истории. Вы указываете Git коммит, где код работал («хорошим»), и коммит, где он сломан («плохим»), а Git последовательно переключается на промежуточный коммит для тестирования, каждый раз сужая диапазон вдвое, пока не останется единственный виновник.

В этой главе рассказывается, как вручную запустить сеанс bisect, как читать прогресс, который Git выводит после каждого ответа, как автоматизировать весь поиск с помощью тестовой команды, как пропускать нетестируемые коммиты и как восстановиться, если вы допустили ошибку.

Определение

git bisect выполняет бинарный поиск между хорошим и плохим коммитом

Почему бинарный поиск

Если ошибка появилась где-то в последних 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 work

Git переключается на коммит, находящийся примерно посередине между ними. Вы собираете и тестируете эту ревизию, затем сообщаете результат:

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 test

Git переключается на каждый промежуточный коммит, выполняет команду, интерпретирует код завершения и останавливается на первом проблемном коммите — ручная разметка не требуется.

Команда может быть любым исполняемым файлом: однострочником, 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 present
git bisect start HEAD v1.4.0
git bisect run ./test.sh
Внимание
Команда git bisect run должна быть идемпотентной и самодостаточной. Если тест оставляет артефакты сборки или изменённые файлы, добавьте шаг очистки, чтобы следующее переключение начиналось с чистого состояния — иначе устаревший бинарный файл может сделать хороший коммит похожим на плохой.

Пропуск нетестируемых коммитов

Иногда проверяемый коммит сломан по не связанной причине — он не компилируется или отсутствует зависимость — и вы действительно не можете сказать «хороший» или «плохой». Скажите Git пропустить его:

git bisect skip

Git выберет соседний коммит и продолжит сужение диапазона. Если в определённой области пропущено слишком много коммитов, 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 использует внутренне.

Практика

Практика
Как 'git bisect' находит плохой коммит?
Как 'git bisect' находит плохой коммит?
Was this page helpful?