Пошук уроків, статей та іншого контенту
Підключите тестовий скрипт до bisect run і прискорите локалізацію регресій у великій історії.
git bisectgit bisect ділить діапазон комітів навпіл і просить визначити, чи є поточний коміт працездатним. У ручному режимі після кожного переходу потрібно запускати тест і вводити результат.
Команда git bisect run автоматизує цей процес:
Git перемикається на черговий коміт.
Запускає вказаний тестовий скрипт.
Аналізує код завершення скрипту.
Позначає коміт як good, bad або skipped.
Переходить до наступної половини історії.
Це особливо корисно, коли регресія знаходиться серед сотень комітів, а перевірка займає кілька секунд або хвилин.
Тестовий скрипт повинен повертати спеціальні коди:
0 — поточний коміт добрий, регресії немає;
1–124 або 126–127 — поточний коміт поганий;
125 — коміт потрібно пропустити, оскільки його неможливо перевірити;
інші коди зазвичай зупиняють виконання bisect.
Найважливіше правило:
Не використовуйте ненульовий код для помилок середовища без додаткової обробки. Інакше Git може помилково позначити коміт як такий, що містить регресію.
Наприклад:
тест не пройшов — 1;
не вдалося встановити залежності або підготувати середовище — 125;
тест пройшов — 0.
Припустімо, що проєкт має npm-тест, який повертає коректний код завершення:
npm test -- --runInBandСтворимо файл scripts/bisect-test.sh:
#!/usr/bin/env bash
set -u
# Якщо середовище не підготовлене, цей коміт неможливо перевірити.
if ! command -v npm >/dev/null 2>&1; then
echo "npm не знайдено в PATH" >&2
exit 125
fi
if [ ! -d node_modules ]; then
echo "Залежності не встановлені" >&2
exit 125
fi
# Не використовуємо set -e, щоб самостійно обробити код npm test.
if npm test -- --runInBand; then
exit 0
else
status=$?
# Код 125 має спеціальне значення для git bisect.
if [ "$status" -eq 125 ]; then
exit 125
fi
# Будь-яка помилка тестів означає регресію.
exit 1
fiЗробіть файл виконуваним:
chmod +x scripts/bisect-test.shПеревірте скрипт вручну:
./scripts/bisect-test.sh
echo $?Перед запуском bisect переконайтеся, що залежності встановлені в робочому дереві:
npm ciЯкщо залежності змінюються разом з історією проєкту, одного запуску npm ci може бути недостатньо. У такому випадку скрипт може встановлювати залежності для кожного коміту, але це значно сповільнить пошук. Спочатку варто перевірити, чи справді залежності є причиною проблеми.
Спочатку потрібно вказати коміт, де помилка гарантовано присутня, і коміт, де її ще немає:
git status
git bisect start
git bisect bad HEAD
git bisect good v2.4.0Тепер запустіть автоматизацію:
git bisect run ./scripts/bisect-test.shGit сам виконуватиме приблизно такі дії:
running './scripts/bisect-test.sh'
Bisecting: 42 revisions left to test after this (roughly 6 steps)
[abc1234] Update request validation
running './scripts/bisect-test.sh'
...Кожен запуск тесту перевіряє поточний коміт, на який Git тимчасово перемкнув робоче дерево. Не потрібно додатково передавати ідентифікатор коміту скрипту.
Після завершення Git покаже перший коміт, у якому з'явилася проблема:
abc1234 is the first bad commit
commit abc1234
Author: Developer <developer@example.com>
Date: ...
Update request validationПісля аналізу результату завершіть режим пошуку:
git bisect resetЦе поверне репозиторій до коміту, з якого було розпочато bisect.
Для регресії часто не потрібно запускати весь набір тестів. Якщо проблема стосується лише валідації замовлення, краще запускати один стабільний тест:
#!/usr/bin/env bash
set -u
if [ ! -d node_modules ]; then
echo "Залежності не встановлені" >&2
exit 125
fi
if npm test -- test/order-validation.test.js --runInBand; then
exit 0
else
status=$?
if [ "$status" -eq 125 ]; then
exit 125
fi
exit 1
fiЧим коротший і стабільніший тест, тим швидше завершиться бісекція. Водночас тест має точно відтворювати симптом регресії. Якщо він перевіряє іншу поведінку, Git може знайти коміт, який не має відношення до справжньої проблеми.
Деякі коміти неможливо перевірити:
коміт не збирається через тимчасову несумісність;
відсутня потрібна версія інструмента;
тест залежить від файлу, який з'явився лише в іншій гілці;
зламане зовнішнє середовище, а не код проєкту.
У такому випадку скрипт повинен повернути 125:
if ! npm ci; then
echo "Не вдалося встановити залежності, пропускаємо коміт" >&2
exit 125
fiGit спробує не використовувати цей коміт для висновку про перший поганий коміт.
Не повертайте 125, якщо тест просто не пройшов. Звичайне падіння тесту — це ознака регресії, тому воно має повертати 1.
Автоматизація припускає, що тест має однаковий результат для одного й того самого коміту. Нестабільний тест може зіпсувати весь пошук.
Перед git bisect run перевірте тест кілька разів на поточному коміті:
for i in 1 2 3 4 5; do
./scripts/bisect-test.sh
doneЯкщо один і той самий код іноді повертає 0, а іноді 1, спочатку усуньте нестабільність або тимчасово замініть тест на більш детермінований.
Проблемними можуть бути:
залежність від поточного часу;
випадкові значення без фіксованого seed;
мережеві запити;
спільний стан між тестами;
паралельний запуск тестів;
залежність від локальних змінних середовища.
Для бісекції краще запускати лише потрібний тест і вимкнути зайвий паралелізм.
Git зберігає виконані позначки. Переглянути їх можна так:
git bisect logПриклад журналу:
git bisect start
# bad: [f91a2cd] Current main
git bisect bad f91a2cd
# good: [1a2b3c4] Release 2.4.0
git bisect good 1a2b3c4
# bad: [abc1234] Update request validation
git bisect bad abc1234Журнал корисний, якщо тестовий скрипт був налаштований неправильно або процес потрібно відтворити. Переглянути залишкову кількість комітів можна командою:
git bisect visualizeПісля завершення не забудьте виконати:
git bisect resetЯкщо Git повідомляє про неможливість запуску файлу:
chmod +x scripts/bisect-test.shТакож можна запустити скрипт через інтерпретатор:
git bisect run bash scripts/bisect-test.shset -e без обробки помилки тестуТакий скрипт може завершуватися одразу після падіння команди:
set -e
npm test
status=$?Рядок status=$? у цьому випадку не буде виконано. Для git bisect run це не завжди проблема, але ви втрачаєте контроль над кодом завершення та обробкою спеціального коду 125.
Краще явно обробити команду через if:
if npm test; then
exit 0
else
exit 1
fiЯкщо npm ci, база даних або інший обов'язковий крок не працює, не повертайте звичайний код помилки тесту. Інакше Git вважатиме коміт поганим:
npm ci
exit 1Для проблеми, яка не пов'язана з кодом коміту, використовуйте:
exit 125Тест не повинен залишати зміни, які впливають на наступну ітерацію:
змінені файли конфігурації;
згенеровані вихідні файли;
змінені міграції;
службові файли в репозиторії.
Git перемикається між комітами, тому залишені зміни можуть завадити checkout або вплинути на результат наступного тесту.
Якщо тест надто широкий, він може падати через незалежну проблему. Якщо тест надто вузький, він може не помітити регресію.
Перед автоматичним запуском перевірте три властивості:
тест проходить на відомому доброму коміті;
тест падає на відомому поганому коміті;
результат повторюється кілька разів.
bisectПісля запуску git bisect start команди Git працюють у спеціальному режимі. Якщо потрібно тимчасово припинити пошук:
git bisect log > bisect.log
git bisect resetПізніше його можна відновити, повторивши початкові команди та застосувавши журнал вручну.
git bisect run запускає тестовий скрипт для кожного перевірюваного коміту.
Код 0 означає good, ненульовий код до 127, крім 125, — bad.
Код 125 використовують для комітів, які неможливо перевірити.
Скрипт повинен мати стабільний результат і не змінювати робоче дерево.
Перед запуском перевірте тест на відомому доброму та поганому комітах.
Після завершення пошуку виконайте git bisect reset.