Как стать автором
Обновить

git bisect: путешествие по времени и багам

Время на прочтение5 мин
Количество просмотров18K
Автор оригинала: Remi Mercier

Добрый день, меня зовут Павел Поляков, я Principal Engineer в каршеринг компании SHARE NOW, в Гамбурге в ?? Германии. А еще я автор Telegram-канала Хороший разработчик знает, где рассказываю обо всем, что должен знать хороший разработчик.

Сегодня я хочу поговорить про git bisect , инструмент, который помогает найти момент, когда появился баг. Считаю, что Middle+ разработчики должны иметь его в своем арсенале. Это перевод оригинальной статьи.

Git bisect: путешествие по времени и багам

Не важно насколько хорошо ваш проект покрыт тестами, вы не можете протестировать все.

Однажды вы создадите регрессию в вашем приложении и не заметите это сразу. А когда вы, наконец, заметите что какая-то фича не работает, то может быть сложно понять почему это произошло. Еще сложнее это сделать, когда над проектом вы работаете не одни.

Самое время познакомиться с git bisect.

Готовы путешествовать во времени по своему коду?

Не эффективный метод дебага — проверять коммит за коммитом

Один раз ситуация, которую я описал выше, произошла со мной.

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

Просматривать свои коммиты в обратном порядке, это реальный пример квадратичного поиска. Сложность квадратичного поиска 0(n^2), то есть, если количество данных увеличится в 10 раз, то мы на поиск мы потратим в 100 раз больше времени.

Это может сработать, если у вас пара коммитов. Но чем больше коммитов вам нужно проверить, те больше времени это займет, причем это экспоненциальный рост.

С другой стороны, git bisect использует бинарный поиск для поиска среди ваших коммитов. И это быстрее!

Хорошо, а что такое бинарный поиск?

Бинарный поиск работает с отсортированной информацией. Вместо проверки элементов один за другим, от первого к последнему, алгоритм начинает сразу с элемента в середине.

В зависимости от условий вашего поиска, алгоритм сделает что-то из списка:

  • вернет текущий элемент

  • проверит все элементы слева о текущего

  • проверит все элементы справа от текущего

На каждой итерации алгоритм проверяет средний элемент в списке, который постоянно уменьшается.

TL;DR: бинарный поиск не проверяет каждый элемент в списке, он проверяет только часть. И все равно находит результат.

git bisect работает аналогично.

Эффективный метод дебага: git bisect

Сейчас ваше приложение не работает как положено. Но мы знаем, что два месяца назад эта фича работала. Какой-то коммит, который мы добавили в течении этого времени внес регрессию.

В чем проблема? Мы не знаем когда это произошло.

Есть один коммит, который разделяет хронологию вашего приложения на до и после:

  • все что было ДО этого плохого коммита — ваше приложение работало отлично

  • все что было ПОСЛЕ этого плохого коммита — ваше приложение поломано

git bisect использует бинарный поиск, чтобы найти коммит, который привел к регрессии.

Он использует самый свежий "плохой" коммит и последний известный "хороший" коммит как диапазон, который нужно проверить.

git bisect выбирает коммит в середине этого списка и просит вас указать — это "хороший" или "плохой" коммит. Присутствует ли регрессия в этом коммите? Он продолжает сужать список, пока не найдет тот самый коммит, который привел к регрессии.

Давайте попробуем:

➜  my-app git:(main) ✗ git bisect start
➜  my-app git:(main|BISECTING) ✗ git bisect bad
➜  my-app git:(main|BISECTING) ✗ git bisect good ae998022
Bisecting: 4 revisions left to test after this (roughly 4 steps)
[02ca345f3e29217bb6553] Refactor the asset pipeline

Теперь разберем подробно:

  • git bisect start запускает режим bisect

  • git bisect bad — говорит bisect, что в текущем HEAD мы уже наблюдаем регрессию

  • git bisect good <commit sha> — говорит bisect о последнем "хорошем" коммите, когда приложение работало правильно

  • Bisecting: 4 revisions left... — примерное количество шагов, которые понадобятся

  • [02ca345f3e29217bb6553] Refactor ...: коммит на который ваш репозиторий указывает сейчас

Вместо того чтобы проверять коммиты один за другим, git bisect сразу прыгает в середину вашего списка (здесь, коммит 02ca345f3e29217bb6553) и вы можете проверить, как ваш код работал во время этого коммита. Круто!

Теперь вы можете запустить ваше приложение, запустить тесты. Может быть вручную проверить работает ли фича на локальном окружении. Я повторяю, проверьте вручную есть ли сейчас баг. Это важно!

Почему я настаиваю? Потому что, когда я использовал bisect впервые, у меня в голове был кандидат на "плохой" коммит. Вместо того, чтобы проверить мое приложение вручную на каждом этапе, я просто говорил bisect свое мнение, о том есть ли сейчас регрессия. В итоге git bisect примел меня к тому самому коммиту, который я и подозревал.

Однако, когда я начал использовать git bisect правильно, я понял, что ошибался. Тот коммит был невиновен. Я быстро нашел настоящего виновника.

Но вернемся к текущему bisect.

➜  my-app git:(main) ✗ git bisect start
➜  my-app git:(main|BISECTING) ✗ git bisect bad
➜  my-app git:(main|BISECTING) ✗ git bisect good ae998022
Bisecting: 4 revisions left to test after this (roughly 4 steps)
[02ca345f3e29217bb6553] Refactor the asset pipeline

➜  my-app git:((02ca345f3...)|BISECTING) ✗ git bisect bad
Bisecting: 11 revisions left to test after this (roughly 3 steps)
[76c502e15dba8ac5b] Add new feature

Сейчас приложение на коммите 76c502e15dba8ac5b.

Если сейчас приложение не работает, значит баг был внесен раньше. Когда мы пишем git bisect bad, git besect понимает, что сейчас приложение не работает и перемещается на средний коммит "слева" от текущего. То есть идет дальше в прошлое.

Если приложение работает, git bisect good скажет git bisect исследовать "правую" часть, коммиты в будущем.

➜  my-app git:(main) ✗ git bisect start
➜  my-app git:(main|BISECTING) ✗ git bisect bad
➜  my-app git:(main|BISECTING) ✗ git bisect good ae998022
Bisecting: 4 revisions left to test after this (roughly 4 steps)
[02ca345f3e29217bb6553] Refactor the asset pipeline

➜  my-app git:((02ca345f3...)|BISECTING) ✗ git bisect bad
Bisecting: 11 revisions left to test after this (roughly 3 steps)
[76c502e15dba8ac5b] Add new feature
➜  my-app git:((76c502e15...)|BISECTING) ✗ git bisect bad
Bisecting: 3 revisions left to test after this (roughly 2 steps)
[e7e6f2ab20a7f9b] Merge branch 'new-payment-system' into 'main'
➜  my-app git:((e7e6f2ab2...)|BISECTING) ✗ git bisect bad
Bisecting: 1 revision left to test after this (roughly 1 step)
[4a6d8943db4e2d] Change CORS
➜  my-app git:((4a6d8943d...)|BISECTING) ✗ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 1 step)
[996e5a376c7b9] Update GEMFILE
➜  my-app git:((a7c40a681...)|BISECTING) ✗ git bisect bad
a7c40a6818c34f1ea1 is the first bad commit
commit a7c40a6818c34f1ea1
Merge: xxx xxx
Author: Remi Mercier
Date:   Tue Aug 3 13:51:20 2021 +0000

Отступление: если вам необходимо вручную проверять приложение, то, скорее всего, лучше написать тест. В случае моего бага, я написал интеграционный тест с моками ответов от двух сервисов.

Все это намного быстрее чем проверять каждый коммит и искать иголку в стоге сена!

Если вы не можете проверить коммит который выбрал git bisect, например в нем приложение вообще не компилировалось, то вы можете использовать git bisect skip и git bisect перейдет к другому коммиту.

Хотите узнать больше? Посмотрите официальную документацию по git bisect.

Использовали git bisect раньше? Пишите в комментариях, мне интересно.

А еще...

Здесь говорю опять я, Павел. В конце еще раз приглашу вас в свой Telegram-канал. На канале Хороший разработчик знает я минимум три раза в неделю простым языком рассказываю про свой опыт, хард скиллы и софт скиллы. Я 15+ лет в IT, мне есть чем поделиться. Все это нужно разработчику, чтобы делать свою работу хорошо, быть востребованным на рынке и получать высокую компенсацию.

Спасибо ?

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 9: ↑5 и ↓4+4
Комментарии12

Публикации