Git bisect. Ищем баги с помощью гита

октябрь 6 , 2019

Сколько раз такое было? Начинаешь делать новую задачу, создаешь ветку от мастера, сидишь, коммитишь себе и вдруг - бац! Вылезает бага. Причем из старого функционала, то, что раньше точно работало.

Начинаешь разбираться, откуда эта бага взялась. Для начала переключаешься на мастер, проверяешь - там работает. Ага, значит, это сам в своей ветке накосячил. Надо искать у себя. Каким образом - есть разные варианты.

Если ты хорошо знаешь модуль, где всплыла бага, то возможно, достаточно будет немного посидеть и подумать. Сузить круг поиска, найти куски кода, где вероятнее всего, бага и закралась. Способ работает, но реже, чем хотелось бы.

Другой вариант, засесть и последовательно анализировать цепочку вызовов функций, отслеживать переменные в отладчике, разбираться во взаимосвязях отдельных частей системы. Способ тоже неплохой, но очень трудозатратный.

Думаешь дальше. Так, у нас же гит, коммиты и все такое. Коммиты для того и придуманы, чтобы писать код итеративно. Раз есть коммиты, значит, в какой-то из них и влезла бага - хорошо бы этот коммит найти.

Вроде нет проблем, переключаться между коммитами можно. git checkout hash_commit и все. Переключился на предыдущий коммит, проверил. Если баги нет, значит, косяк в последнем коммите, начинаешь искать там. А если бага осталась, значит, проблема еще раньше - переключаешься на коммит раньше, снова проверяешь. И так пока не найдешь проблемный коммит.

Вроде звучит все просто. Но проблема в том, что это годится, если в ветке 3 коммита, их и перебрать можно. А если 10? А если 50 или 100? Ну, например, ветка долгоживущая. Что теперь, по очереди всю сотню перебирать? А если бага в самом начале случилась? Двигаться с конца?

Тут вспоминаем, что мы вообще-то программисты и алгоритмы умеем. А еще вспоминаем игру, которой можно сильно удивить любого первоклассника. Мол, давай ты загадаешь число от 1 до 100, а я буду пытаться угадать. Я называю число, а ты говоришь, твое задуманное больше или меньше. И спорим, что за 7 попыток угадаю? За 7, а не за 100! Чудеса.

Конечно, мы понимаем простой принцип этой игры и знаем, как называть числа, каждый раз сужая варианты ровно в 2 раза. Было бы неплохо использовать эту магию и при поиске багов. Но только неохота руками вылавливать коммиты и прыгать по истории гита взад и вперед. На наше счастье все это уже сделано до нас.

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

Давайте посмотрим на примере, как это работает.

Я взял наш проект интернет-магазина, создал новую ветку и накомитил туда 8 коммитов. Вот так это выглядит в PhpStorm

Коммиты сделаны от балды, но пронумерованы от 1 до 8. Это сделал, чтобы было удобнее смотреть, как git bisect делает свои переключения. Будем следить шаг за шагом.

В один из этих коммитов я внес злую багу, но в какой именно - не скажу. Мы проведем расследование с помощью git bisect и найдем зловреда. Если интересно, бага заключается в том, что при клике "Добавить в корзину" товар не добавляется, а выскакивает alert('Error'). Да, на такие "баги" натравливать bisect смешно, тут простой ctrl+F спасет, но мы же понимаем, что реальные баги не такие простые.

Начинаем искать. Открываем консоль и вбиваем туда git bisect start. Это первое, мы говорим, мол, bisect, давай начинай. Дальше второе, пишем git bisect bad - это означает, что текущий коммит у нас "плохой", с багой. И третье - нужно указать "хороший коммит", тот, где баги еще не было. У меня это будет коммит №1 с хэшем f6f2339...
Команда git bisect good f6f2339ba01331a7d7ec7e1324616101fe516199

Как мы и ожидаем, git bisect переключает нас на середину - на коммит №4

Проверяем добавление товара в браузере, ага, бага осталась. Пишем в консоли, git bisect bad. То есть больше никаких хэшей не упоминаем, только говорим, плохой коммит или хороший. Дальше git bisect разберется за нас. Вот что происходит в консоли

Нас кинули на третий коммит. Чтобы убедиться, смотрим в PhpStorm

Проверяем - опять есть бага. Снова пишем git bisect bad и нас переключают на коммит №2

Проверяем - баги нет. Пишем теперь git bisect good и опа! Ну вы, наверно, уже догадались :)

is the first bad commit. Автор, дата и message коммита - весь расклад. Зловред найден, это коммит №3. Хочется посмотреть, что же в нем такого написано. Но сейчас мы находимся на коммите №2, поэтому третий даже не видим в PhpStorm. Да и с git bisect мы закончили, нужно завершить его работу и вернуться в нормальное состояние. Пишем git bisect reset и возвращаемся в начало, к коммиту №8.

Давайте же посмотрим на этот третий коммит. Откроем git diff в PhpStorm и видим волшебный код

Да, я в функцию клика по кнопке "Добавить" просто написал alert('Error') и return false. Не делайте так :-)
Все, осталось убрать эти строчки и баг пофикшен.

Конечно, многое зависит от того, какой у вас будет искомый коммит. Если там изменений на 500 строк в 30 файлах, то искать сам баг будет непросто. Но все равно легче, когда знаем, что косяк именно в этом коммите. Кстати, это еще один аргумент в пользу того, чтобы делать коммиты как можно меньше. Маленькие коммиты легче читать и проще отлаживать. Но в любом случае, знание конкретного коммита облегчит поиск и исправление проблемы.

Вот и все. Такой он, git bisect, страшно звучит, но просто работает.

Всем поменьше багов и любите гит :-)

Все статьи о git

Заходите в группу в контакте - https://vk.com/webdevkin
Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
Истории из жизни айти и обсуждение кода.
Как Вам статья? Оцените!