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

НАЗВА

git-bisect - Використовуйте бінарний пошук, щоб знайти коміт, який призвів до помилки

СИНОПСИС

git bisect <subcommand> <options>

ОПИС

Команда приймає різні підкоманди та різні опції залежно від підкоманди:

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 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 можна використовувати для пошуку коміту, який змінив будь-яку властивість вашого проєкту; наприклад, коміт, який виправив помилку, або коміт, який покращив продуктивність бенчмарка. Для підтримки цього більш загального використання замість «хороший» та «поганий» можна використовувати терміни «старий» та «новий», або ви можете обрати власні терміни. Дивіться розділ «Альтернативні терміни» нижче для отримання додаткової інформації.

Основні команди бісекції: старт, погано, добре

Наприклад, припустимо, що ви намагаєтеся знайти коміт, який зламав функцію, яка, як відомо, працювала у версії 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 залишить вас на поточному коміті bisection та взагалі уникне перемикання комітів.

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

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

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

У цьому більш загальному випадку, ви надаєте 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, виконайте таку команду під час процесу поділу на дві частини (підкоманду view можна використовувати як альтернативу visualize):

$ 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

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

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

Наприклад:

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

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

Розділити корабель навпіл

Замість того, щоб самостійно вибирати найближчий коміт, ви можете попросити 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 (включно) слід пропустити.

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

Ви можете ще більше скоротити кількість спроб, якщо знаєте, яка частина дерева пов’язана з проблемою, яку ви відстежуєте, вказавши параметри 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

Розріз на дві частини

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

$ 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/ у заголовковий файл або «версія, яка не має цього коміту, потребує цього патчу, щоб вирішити іншу проблему, яка не цікавить цю бісекцію»), застосовані до тестованої версії.

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

ОПЦІЇ

--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                   # вийти з сеансу бісекти
  • Автоматично розділити невдачу тесту між початком та 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».

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

    $ 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]