українська мова ▾ Topics ▾ Latest version ▾ git-bisect last updated in 2.52.0

НАЗВА

git-bisect —Бінарний пошук для визначення коміту, в якому з’явилася помилка

СИНОПСИС

git bisect start [--term-(bad|new)=<term-new> --term-(good|old)=<term-old>]
		   [--no-checkout] [--first-parent] [<bad> [<good>…​]] [--] [<pathspec>…​]
git bisect (bad|new|<term-new>) [<rev>]
git bisect (good|old|<term-old>) [<rev>…​]
git bisect terms [--term-(good|old) | --term-(bad|new)]
git bisect skip [(<rev>|<range>)…​]
git bisect next
git bisect reset [<commit>]
git bisect (visualize|view)
git bisect replay <logfile>
git bisect log
git bisect run <cmd> [<arg>…​]
git bisect help

ОПИС

Ця команда використовує алгоритм бінарного пошуку, щоб визначити, який саме коміт в історії вашого проєкту спричинив появу помилки. Щоб скористатися нею, спочатку потрібно вказати «поганий» коміт, який, як відомо, містить помилку, та «хороший» коміт, який, як відомо, був зроблений до появи помилки. Потім git bisect вибирає коміт між цими двома крайніми точками і запитує вас, чи є вибраний коміт «хорошим» чи «поганим». Програма продовжує звужувати діапазон, доки не знайде точний коміт, який спричинив зміну.

Фактично, git bisect можна використовувати для пошуку коміту, який змінив будь-яку властивість вашого проєкту; наприклад, коміт, який виправив помилку, або коміт, який покращив продуктивність бенчмарка. Для підтримки цього більш загального використання замість «хороший» та «поганий» можна використовувати терміни «старий» та «новий», або ви можете обрати власні терміни. Дивіться розділ «Альтернативні терміни» нижче для отримання додаткової інформації.

Основні команди бісекції: start, bad, good

Наприклад, припустимо, що ви намагаєтеся знайти коміт, який зламав функцію, яка, як відомо, працювала у версії v2.6.13-rc2 вашого проєкту. Ви починаєте бісекцію наступним чином:

$ git bisect start
$ git bisect bad                 # Поточна версія — погана
$ git bisect good v2.6.13-rc2    # v2.6.13-rc2 є відомою гарною версією

Після того, як ви вказали хоча б один поганий та один хороший коміт, git bisect вибирає коміт посередині цього діапазону історії, перевіряє його та виводить щось подібне до наступного:

Розділення: після цього залишилося протестувати 675 змін (приблизно 10 кроків)

Тепер вам слід скомпілювати отриману версію та протестувати її. Якщо ця версія працює правильно, зробіть

$ git bisect good

Якщо ця версія пошкоджена, зробіть

$ git bisect bad

Тоді git bisect відповість чимось на кшталт

Розділення: після цього залишилося протестувати 337 версій (приблизно 9 кроків)

Продовжуйте повторювати процес: скомпілюйте дерево, протестуйте його та, залежно від того, чи воно хороше, чи погане, виконайте git bisect good або git bisect bad, щоб запитати наступний коміт, який потребує тестування.

Зрештою, ревізій, які потрібно перевірити, не залишиться, і команда виведе опис першого некоректного коміту. Посилання refs/bisect/bad залишиться спрямованим на цей коміт.

Скидання бісекції

Після сеансу бісекції, щоб очистити стан бісекції та повернутися до початкового HEAD, виконайте таку команду:

$ git bisect reset

Зазвичай, це поверне ваше дерево до коміту, який було отримано перед git bisect start. (Новий git bisect start також зробить це, оскільки він очищає старий стан бісекції.)

За допомогою необовʼязкового аргументу ви можете повернутися до іншого коміту:

$ git bisect reset <commit>

Наприклад, git bisect reset bisect/bad перевірить першу погану ревізію, тоді як git bisect reset HEAD залишить вас на поточному коміті бісекції та взагалі уникне перемикання комітів.

Альтернативні терміни

Іноді вам потрібно знайти не той коміт, який спричинив збій, а той, що призвів до переходу від якогось «старого» стану до «нового». Наприклад, ви можете шукати коміт, у якому було впроваджено певне виправлення. Або ж ви шукаєте перший коміт, у якому імена файлів вихідного коду нарешті були приведені у відповідність до стандартів іменування вашої компанії. Чи будь-що інше.

У таких випадках використання термінів «хороший» і «поганий» для позначення «стану до зміни» та «стану після зміни» може викликати значну плутанину. Тому замість «хороший» і «поганий» можна використовувати терміни «старий» і «новий» відповідно. (Але зверніть увагу, що в одній сесії не можна змішувати «хороший» і «поганий» з «старим» і «новим».)

У цьому більш загальному випадку ви надаєте git bisect «новий» комміт, який має певну властивість, та «старий» комміт, який цієї властивості не має. Кожного разу, коли git bisect перевіряє коміт, ви перевіряєте, чи має цей коміт цю властивість. Якщо має, позначте коміт як «новий»; інакше позначте його як «старий». Коли бісекція завершиться, git bisect повідомить, який коміт ввів цю властивість.

Щоб використовувати "old" та "new" замість "good" та "bad", потрібно виконати git bisect start без комітів як аргументу, а потім виконати такі команди для додавання комітів:

git bisect old [<rev>]

щоб вказати, що коміт було здійснено до бажаної зміни, або

git bisect new [<rev>...]

щоб вказати, що це було після.

Щоб отримати нагадування про терміни, що використовуються на даний момент, скористайтеся

git bisect terms

Ви можете отримати лише старий термін за допомогою команд git bisect terms --term-old або git bisect terms --term-good; команди git bisect terms --term-new та git bisect terms --term-bad можна використовувати, щоб дізнатися, як називаються коміти, що з’явилися пізніше за шукану зміну.

Якщо ви хочете використовувати власні терміни замість "поганий"/"добрий" або "новий"/"старий", ви можете вибрати будь-які назви (окрім наявних субкоманд бісекції, таких як reset, start тощо), розпочавши бісекцію за допомогою

git bisect start --term-old <term-old> --term-new <term-new>

Наприклад, якщо ви шукаєте коміт, який запровадив регресію продуктивності, ви можете використовувати

git bisect start --term-old fast --term-new slow

Або якщо ви шукаєте коміт, який виправив помилку, ви можете використовувати

git bisect start --term-new fixed --term-old broken

Потім використовуйте git bisect <term-old> та git bisect <term-new> замість git bisect good та git bisect bad для позначення комітів.

Візуалізація/перегляд бісекції

Щоб переглянути підозрювані елементи, що залишилися в «gitk», під час процесу бісекції виконайте таку команду (як альтернативу команді visualize можна використовувати субкоманду view):

$ git bisect visualize

Git визначає наявність графічного середовища за допомогою різних змінних середовища: DISPLAY, яка встановлюється в середовищах X Window System на системах Unix; SESSIONNAME, яка встановлюється в Cygwin під час інтерактивних сеансів роботи на робочому столі; MSYSTEM, яка встановлюється в Msys2 та Git для Windows; SECURITYSESSIONID, яка може встановлюватися в macOS в інтерактивних сесіях робочого столу.

Якщо жодна з цих змінних середовища не встановлена, замість неї використовується git log. Ви також можете задати параметри командного рядка, такі як -p та --stat.

$ git bisect visualize --stat

Журнал та відтворення бісекції

Після позначення редакцій як хороших або поганих, виконайте таку команду, щоб показати, що було зроблено на даний момент:

$ git bisect log

Якщо ви виявите, що помилилися, вказавши статус редакції, ви можете зберегти вивід цієї команди у файлі, відредагувати його, щоб видалити неправильні записи, а потім виконати такі команди, щоб повернутися до виправленого стану:

$ git bisect reset
$ git bisect replay that-file

Уникнення тестування коміту

Якщо посеред сеансу бісекції ви знаєте, що запропонована ревізія не є гарною для тестування (наприклад, вона не збирається, і ви знаєте, що збій не має нічого спільного з помилкою, яку ви шукаєте), ви можете вручну вибрати сусідній коміт і протестувати його.

Наприклад:

$ git bisect good/bad			# попередній раунд був хорошим чи поганим.
Розділення: після цього залишилося протестувати 337 редакцій (приблизно 9 кроків)
$ git bisect visualize			# ой, це нецікаво.
$ git reset --hard HEAD~3		# спробуйте 3 ревізії перед тим
					# що було запропоновано

Потім скомпілюйте та протестуйте вибрану ревізію, а потім позначте її як хорошу або погану звичайним способом.

Bisect skip

Замість того, щоб самостійно вибирати найближчий коміт, ви можете попросити Git зробити це за вас, виконавши команду:

$ git bisect skip                 # Поточну версію неможливо протестувати

Однак, якщо ви пропустите коміт поруч із тим, який ви шукаєте, Git не зможе точно визначити, який із цих комітів був першим поганим.

Ви також можете пропустити діапазон комітів, замість одного, використовуючи нотацію діапазону. Наприклад:

$ git bisect skip v2.5..v2.6

Це повідомляє процесу bisect, що жодні коміти після v2.5, аж до v2.6 включно, не повинні тестуватися.

Зверніть увагу, що якщо ви також хочете пропустити перший коміт діапазону, вам слід виконати команду:

$ git bisect skip v2.5 v2.5..v2.6

Це повідомляє процесу bisect, що коміти між версіями v2.5 та v2.6 (включно) слід пропустити.

Розділити далі

Зазвичай, після позначення ревізії як хорошої чи поганої, Git автоматично обчислює та перевіряє наступну ревізію для тестування. Однак, якщо вам потрібно явно запросити наступний крок бісекції, ви можете використовувати:

$ git bisect next

Ви можете використовувати це для відновлення процесу бісекції після його переривання шляхом перевірки іншої редакції.

Зменшення бісекції шляхом надання більшої кількості параметрів для початку бісекції

Ви можете ще більше скоротити кількість спроб, якщо знаєте, яка частина дерева повʼязана з проблемою, яку ви відстежуєте, вказавши параметри pathspec під час виконання команди bisect start:

$ git bisect start -- arch/i386 include/asm-i386

Якщо вам заздалегідь відомо більше одного хорошого коміту, ви можете звузити простір для пошуку, вказавши всі хороші коміти одразу після поганого коміту під час виконання команди bisect start:

$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 --
                   # v2.6.20-rc6 is bad
                   # v2.6.20-rc4 and v2.6.20-rc1 are good

Bisect run

Якщо у вас є скрипт, який може визначити, чи поточний вихідний код хороший чи поганий, ви можете виконати біснкцію, виконавши команду:

$ git bisect run my_script arguments

Зверніть увагу, що скрипт (my_script у наведеному вище прикладі) повинен завершитися з кодом 0, якщо поточний вихідний код хороший/старий, і завершитися з кодом від 1 до 127 (включно), крім 125, якщо поточний вихідний код поганий/новий.

Будь-який інший код виходу перерве бісекцію. Слід зазначити, що програма, яка завершується через exit(-1), залишає $? = 255 (див. сторінку довідки exit(3)), оскільки значення обрізається за допомогою & 0377.

Спеціальний код виходу 125 слід використовувати, коли поточний вихідний код неможливо перевірити. Якщо скрипт завершується з цим кодом, поточну ревізію буде пропущено (див. git bisect skip вище). 125 було обрано як найвище розумне значення для цієї мети, оскільки 126 та 127 використовуються оболонками POSIX для сигналізації про певний стан помилки (127 означає команду не знайдено, 126 означає команду знайдено, але вона не є виконуваною — ці деталі не мають значення, оскільки вони є звичайними помилками у скрипті, якщо говорити про bisect run).

Часто ви можете зіткнутися з ситуацією, коли під час сеансу бісекції вам потрібно внести тимчасові зміни (наприклад, s/#define DEBUG 0/#define DEBUG 1/ у файл header або «версія, яка не має цього коміту, потребує цієї латки, щоб вирішити іншу проблему, яка не цікавить цю бісекцію»), застосовані до тестованої версії.

Щоб впоратися з такою ситуацією, після того, як внутрішній git bisect знайде наступну ревізію для тестування, скрипт може застосувати латку перед компіляцією, запустити справжній тест, а потім вирішити, чи пройшла ревізія (можливо, з потрібною латкою) тест, а потім перемотати дерево до початкового стану. Нарешті, скрипт повинен завершитися зі статусом справжнього тесту, щоб цикл команди git bisect run визначив кінцевий результат сеансу бісекції.

ОПЦІЇ

--no-checkout

Не перемикатись на нове робоче дерево при кожній ітерації процесу бісекції. Натомість просто оновлювати посилання з іменем BISECT_HEAD, щоб воно вказувало на коміт, який слід перевірити.

Цей параметр може бути корисним, коли тест, який ви виконували б на кожному кроці, не вимагає активованого дерева.

Якщо репозиторій пустий, передбачається --no-checkout.

--first-parent

При виявленні коміту злиття слід враховувати лише перший батьківський коміт.

При виявленні регресій, що виникли внаслідок злиття гілки, коміт злиття буде ідентифіковано як впровадження помилки, а його предки будуть проігноровані.

Ця опція особливо корисна для уникнення хибних спрацьовувань, коли обʼєднана гілка містила пошкоджені або непридатні для збірки коміти, але саме злиття пройшло нормально.

ПРИКЛАДИ

  • Виконати бісекцію автоматично для пошкодженої збірки між версіями 1.2 та HEAD:

    $ git bisect start HEAD v1.2 --      # HEAD поганий, v1.2 хороший
    $ git bisect run make                # "make" створює застосунок
    $ git bisect reset                   # вийти з сеансу бісекції
  • Виконати бісекцію автоматично для невдалого тесту між origin та HEAD:

    $ git bisect start HEAD origin --    # HEAD поганий, origin хороший
    $ git bisect run make test           # "збірки та тести"
    $ git bisect reset                   # вийти з сеансу бісекції
  • Виконати бісекцію автоматично для збійного тесту:

    $ cat ~/test.sh
    #!/bin/sh
    make || exit 125                     # це пропускає пошкоджені збірки
    ~/check_test_case.sh                 # Чи проходить тест?
    $ git bisect start HEAD HEAD~10 --   # винуватець серед останніх 10
    $ git bisect run ~/test.sh
    $ git bisect reset                   # вийти з сеансу бісекції

    Тут ми використовуємо власний скрипт test.sh. У цьому скрипті, якщо make не вдається, ми пропускаємо поточний коміт. check_test_case.sh повинен мати значення exit 0, якщо тестовий випадок пройде успішно, і exit 1 в іншому випадку.

    Безпечніше, якщо і test.sh, і check_test_case.sh знаходяться поза репозиторієм, щоб запобігти взаємодії між процесами bisect, make та test і скриптами.

  • Виконати бісекцію автоматично з тимчасовими змінами (виправленнями):

    $ cat ~/test.sh
    #!/bin/sh
    
    # налаштувати робоче дерево, обʼєднавши гілку з виправленнями
    # а потім спробуйте побудувати
    if	git merge --no-commit --no-ff hot-fix &&
    	make
    then
    	# запустити тест для конкретного проєкту та повідомити про його стан
    	~/check_test_case.sh
    	status=$?
    else
    	# повідомте абоненту, що це неможливо перевірити
    	status=125
    fi
    
    # скасувати налаштування, щоб дозволити чистий перехід до наступного коміту
    git reset --hard
    
    # повернення контролю
    exit $status

    Це застосовує модифікації з гілки hot-fix перед кожним тестовим запуском, наприклад, у випадку, якщо ваше середовище збірки або тестування змінилося таким чином, що старіші ревізії можуть потребувати виправлення, яке новіші вже потребують. (Переконайтеся, що гілка hot-fix базується на коміті, який міститься у всіх ревізіях, які ви перевіряєте, щоб злиття не втягувало забагато змін, або використовуйте git cherry-pick замість git merge.)

  • Виконати бісекцію автоматично для збійного тесту:

    $ git bisect start HEAD HEAD~10 --   # винуватець серед останніх 10
    $ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
    $ git bisect reset                   # вийти з сеансу бісекції

    Це показує, що можна обійтися без сценарію запуску, якщо написати тест в одному рядку.

  • Знайти неушкоджену частину графа об’єктів у пошкодженому репозиторії

    $ git bisect start HEAD <known-good-commit> [ <boundary-commit> ... ] --no-checkout
    $ git bisect run sh -c '
    	GOOD=$(git for-each-ref "--format=%(objectname)" refs/bisect/good-*) &&
    	git rev-list --objects BISECT_HEAD --not $GOOD >tmp.$$ &&
    	git pack-objects --stdout >/dev/null <tmp.$$
    	rc=$?
    	rm -f tmp.$$
    	test $rc = 0'
    
    $ git bisect reset                   # вийти з сеансу бісекції

    У цьому випадку, коли git bisect run завершиться, bisect/bad посилатиметься на коміт, який має принаймні одного батьківського елемента, граф досяжності якого є повністю прохідним у сенсі, що вимагається git pack objects.

  • Пошук виправлення замість регресії в коді

    $ git bisect start
    $ git bisect new HEAD    # поточний коміт позначено як новий
    $ git bisect old HEAD~10 # Десятий коміт з цього моменту позначено як старий

    або:

    $ git bisect start --term-old broken --term-new fixed
    $ git bisect fixed
    $ git bisect broken HEAD~10

Отримання допомоги

Використовуйте git bisect, щоб отримати короткий опис використання, та git bisect help або git bisect -h, щоб отримати повний опис використання.

GIT

Частина набору git[1]