Git blame что это
Перейти к содержимому

Git blame что это

  • автор:

7.10 Инструменты Git — Обнаружение ошибок с помощью Git

Git предоставляет несколько инструментов, которые помогут вам найти и устранить проблемы в ваших проектах. Так как Git рассчитан на работу с проектом почти любого типа, эти инструменты имеют довольно обобщённые возможности, но часто они могут помочь вам отловить ошибку или её виновника.

Аннотация файла

Если вы обнаружили ошибку в вашем коде и хотите знать, когда она была добавлена и почему, то в большинстве случаев аннотация файла будет лучшим инструментом для этого. С помощью неё для любого файла можно увидеть, каким коммитом последний раз изменяли каждую из строк. Поэтому если вы видите, что некоторый метод в вашем коде работает неправильно, вы можете с помощью команды git blame снабдить файл аннотацией, и таким образом увидеть, когда каждая строка метода была изменена последний раз и кем.

В следующем примере используется git blame , чтобы определить, какой коммит и коммиттер отвечал за строки в Makefile ядра Linux верхнего уровня и, кроме того, использует параметр -L для ограничения вывода аннотации строками с 69 по 82 из этого файла:

$ git blame -L 69,82 Makefile b8b0618cf6fab (Cheng Renquan 2009-05-26 16:03:07 +0800 69) ifeq ("$(origin V)", "command line") b8b0618cf6fab (Cheng Renquan 2009-05-26 16:03:07 +0800 70) KBUILD_VERBOSE = $(V) ^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) endif ^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) ifndef KBUILD_VERBOSE ^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) KBUILD_VERBOSE = 0 ^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) endif ^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) 066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 76) ifeq ($(KBUILD_VERBOSE),1) 066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 77) quiet = 066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 78) Q = 066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 79) else 066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 80) quiet=quiet_ 066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 81) Q = @ 066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 82) endif

Обратите внимание, что первое поле — это неполная SHA-1 сумма последнего коммита, который изменял соответствующую строку. Следующими двумя полями являются значения, извлечённые из этого коммита — имя автора и время создания коммита — таким образом, вы можете легко увидеть кто изменял строку и когда. После этого следуют номер строки и содержимое файла. Обратите внимание на строки со значением ^4832fe2 в поле коммита, так обозначаются те строки, которые были в первом коммите этого файла. Этот коммит был сделан, когда данный файл был впервые добавлен в проект и с тех пор эти строки не были изменены. Немного сбивает с толку то, что вы уже видели в Git, по крайней мере, три различных варианта использования символа ^ для изменения SHA-1 коммита, в данном случае этот символ имеет такое значение.

Другая отличная вещь в Git — это то, что он не отслеживает явно переименования файлов (пользователю не нужно явно указывать какой файл в какой был переименован). Он сохраняет снимки и уже после выполнения самого переименования неявно попытается выяснить, что было переименовано. Одна из интересных возможностей, вытекающих из этого — это то, что вы также можете попросить Git выявить перемещения кода всех других видов. Если передать опцию -C команде git blame , Git проанализирует аннотируемый файл и попытается выяснить откуда изначально появились фрагменты кода, если они, конечно же, были откуда-то скопированы. Например, предположим при реорганизации кода в файле GITServerHandler.m вы разнесли его по нескольким файлам, один из которых GITPackUpload.m . Вызывая git blame с опцией -C для файла GITPackUpload.m , вы можете увидеть откуда изначально появились разные фрагменты этого файла.

$ git blame -C -L 141,153 GITPackUpload.m f344f58d GITServerHandler.m (Scott 2009-01-04 141) f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void) gatherObjectShasFromC f344f58d GITServerHandler.m (Scott 2009-01-04 143) < 70befddd GITServerHandler.m (Scott 2009-03-22 144) //NSLog(@"GATHER COMMI ad11ac80 GITPackUpload.m (Scott 2009-03-24 145) ad11ac80 GITPackUpload.m (Scott 2009-03-24 146) NSString *parentSha; ad11ac80 GITPackUpload.m (Scott 2009-03-24 147) GITCommit *commit = [g ad11ac80 GITPackUpload.m (Scott 2009-03-24 148) ad11ac80 GITPackUpload.m (Scott 2009-03-24 149) //NSLog(@"GATHER COMMI ad11ac80 GITPackUpload.m (Scott 2009-03-24 150) 56ef2caf GITServerHandler.m (Scott 2009-01-05 151) if(commit) < 56ef2caf GITServerHandler.m (Scott 2009-01-05 152) [refDict setOb 56ef2caf GITServerHandler.m (Scott 2009-01-05 153)

Это, действительно, полезно. Обычно вы получаете в качестве изначального коммит, в котором вы скопировали код, так как это первый коммит, в котором вы обращаетесь к этим строкам в этом файле. Но в данном случае Git сообщает вам первый коммит, в котором эти строки были написаны, даже если это было сделано в другом файле.

Бинарный поиск

Аннотирование файла помогает, если вы знаете, где находится проблема и можете начать исследование с этого места. Если вы не знаете, что сломано, а с тех пор как код работал, были сделаны десятки или сотни коммитов, вы вероятно воспользуетесь командой git bisect . Эта команда выполняет бинарный поиск по истории коммитов для того, чтобы помочь вам как можно быстрее определить коммит, который создал проблему.

Допустим, вы только что развернули некоторую версию вашего кода в боевом окружении и теперь получаете отчёты о некоторой ошибке, которая не возникала в вашем разработческом окружении, и вы не можете представить, почему код ведет себя так. Вы возвращаетесь к вашему коду и выясняете, что можете воспроизвести проблему, но всё ещё не понимаете, что работает неверно. Вы можете воспользоваться бинарным поиском, чтобы выяснить это. Во-первых, выполните команду git bisect start для запуска процесса поиска, а затем используйте git bisect bad , чтобы сообщить Git, что текущий коммит сломан. Затем, используя git bisect good [good_commit] , вы должны указать, когда было последнее известное рабочее состояние:

$ git bisect start $ git bisect bad $ git bisect good v1.0 Bisecting: 6 revisions left to test after this [ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] Error handling on repo

Git выяснил, что произошло около 12 коммитов между коммитом, который вы отметили как последний хороший коммит (v1.0), и текущим плохим коммитом, и выгрузил вам один из середины. В этот момент вы можете запустить ваши тесты, чтобы проверить присутствует ли проблема в этом коммите. Если это так, значит она была внесена до выгруженного промежуточного коммита, если нет, значит проблема была внесена после этого коммита. Пусть в данном коммите проблема не проявляется, вы сообщаете об этом Git с помощью git bisect good и продолжаете ваше путешествие:

$ git bisect good Bisecting: 3 revisions left to test after this [b047b02ea83310a70fd603dc8cd7a6cd13d15c04] Secure this thing

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

$ git bisect bad Bisecting: 1 revisions left to test after this [f71ce38690acf49c1f3c9bea38e09d82a5ce6014] Drop exceptions table

Этот коммит хороший и теперь Git имеет всю необходимую информацию для определения того, где была внесена ошибка. Он сообщает вам SHA-1 первого плохого коммита и отображает некоторую информацию о коммите и файлах, которые были изменены в этом коммите, так, чтобы вы смогли разобраться что же случилось, что могло привнести эту ошибку:

$ git bisect good b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04 Author: PJ Hyett Date: Tue Jan 27 14:48:32 2009 -0800 Secure this thing :040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730 f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M config

Когда вы закончили бинарный поиск, нужно выполнить git bisect reset для того, чтобы вернуть HEAD туда, где он был до начала поиска, иначе вы останетесь в, довольно, причудливом состоянии:

$ git bisect reset

Это мощный инструмент, который помогает вам за считанные минуты проверить сотни коммитов на возможность внесения ошибки. В действительности, если у вас есть скрипт, который будет возвращать 0 если проект находится в рабочем состоянии и любое другое число в обратном случае, то вы можете полностью автоматизировать git bisect . Сперва, вы снова сообщаете границы бинарного поиска, указывая известные плохие и хорошие коммиты. Вы можете сделать это, передавая их команде bisect start — первым аргументом известный плохой коммит, а вторым известный хороший коммит:

$ git bisect start HEAD v1.0 $ git bisect run test-error.sh

Это приведёт к автоматическому выполнению test-error.sh на каждый выгруженный коммит до тех пор, пока Git не найдёт первый сломанный коммит. Вы также можете использовать что-то вроде make или make tests , или что-то ещё, что у вас есть для запуска автоматизированных тестов.

Пара приемов работы с git

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

Но в использовании какого-то инструмента возникает такой момент (особенно, если изучение его идет по разным факам, форумам, статьям в интернете), когда вроде бы знания по работе с ним уже получены достаточно, но все равно чувствуешь, что в каких-то моментах ты немного плаваешь. Значит настало время взять в руки нормальную книгу и начать ее читать от корки до корки.

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

Но статья, на самом деле, не об этом. Я хочу рассказать про две замечательные команды git, которые я недавно для себя открыл. Это git blame и git bisect

Аннотация файла

Не редко случается ситуация, когда находишь в коде какой-то баг у жутко становится интересно, кто же это все написал и когда. (Еще конечно хочется знать, что он при этом думал и каким местом давил на кнопки, но тут конечно гит бессилен)

git blame позволяет посмотреть когда и кем редактировалась каждая строка файла в последний раз.

git blame -L 12,22 products.php

ebf9cf99 (vasia 2011-11-16 15:07:52 +0400 260)$templates = $controller->getTemplates(); ebf9cf99 (vasia 2011-11-16 15:07:52 +0400 261) foreach($templates as $value)

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

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

git blame -L 10,19 -C Controller.php

3351a8dc /logistics/pages/Controller.php (vasia 2012-01-24 15:26:04 +0400 10) 0cb0d219 /orders/pages/Controller.php vasia 2012-01-13 09:51:54 +0400 16)

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

Бинарный поиск

Вторая возможность, про которую я хотел бы рассказать — это возможность бинарного поиска по коммитам. Для примера приведу следующую ситуацию. В нашем проекте поломался какой-то функционал, в чем конкретно проблема мы понять не можем, но точно знаем, что в прошлом релизе этот функционал точно работал. Так вот команда bisect позволяет нам легко откатить проект на заданное число коммитов и найти тот коммит, в котором неуловимый баг проявляется в первый раз.

Во-первых, запускаем механизм поиска и устанавливаем значение, что текущее состояние проекта нерабочее

git bisect start git bisect bad

Далее откатываемся на рабочее состояние проекта — на 10 коммитов назад по истории

git bisect good HEAD~10

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

git bisect good

Эта команда перематывает состояние проекта в середину, между хорошим коммитом и плохим, т. е. Сейчас мы находимся в пяти коммитах назад по истории. Если баг проявляется, то он находится до текущего коммита, если нет — то после. С каждой такой итерацией расстояние уменьшается в два раза, пока мы не находим плохой коммит (а главное — его автора, к сожалению, это его опять сделали мы).

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

git bisect reset

Вернувшись к вступлению, хочу сказать, что в обучении гиту для меня такой книгой, которая расставила бы все точки над ё, стала вот эта. Может быть не самое подробное изложение, но, на мой взляд, для перехода от состояния «я могу это сделать» до состояния «я могу это сделать и понимаю, почему нужно делать именно так» очень хороший вариант. Есть и ее перевод (правда не совсем полный) на русский язык.

На этом рассказ свой хочу закончить, надеюсь описанный функционал будет полезен в работе не только тем, кто только открывает для себя git.

UPD.
Для меркуриал данный функционал тоже существует, спасибо retran
blame — hg annotate
А для поиска есть специальный плагин — mercurial.selenic.com/wiki/BisectExtension

Для svn есть
svn blame TARGET[@REV]

A3.7 Приложение C: Команды Git - Отладка

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

git bisect

Команда git bisect — это чрезвычайно полезная утилита для поиска коммита в котором впервые проявился баг или проблема с помощью автоматического бинарного поиска.

О ней упоминается только в разделе Бинарный поиск главы 7, где она полностью и раскрыта.

git blame

Команда git blame выводит перед каждой строкой файла SHA-1 коммита, последний раз менявшего эту строку и автора этого коммита. Это помогает в поисках человека, которому нужно задавать вопросы о проблемном куске кода.

Эта команда полностью разобрана в разделе Аннотация файла главы 7.

git grep

Команда git grep используется для поиска любой строки или регулярного выражения в любом из файлов вашего проекта, даже в более ранних его версиях.

Она полностью разобрана в разделе Команда git grep главы 7 и упоминается лишь там.

Git blame что это

Команда git blame это действительно полезная команда, чтобы найти того кто изменил определенную часть файла. Вы просто выполните 'git blame [filename]' и получите вывод всех данных файла включая sha значение последнего коммита, дату и автора каждой строки файла.

$ git blame sha1_file.c . 0fcfd160 (Linus Torvalds 2005-04-18 13:04:43 -0700 8) */ 0fcfd160 (Linus Torvalds 2005-04-18 13:04:43 -0700 9) #include "cache.h" 1f688557 (Junio C Hamano 2005-06-27 03:35:33 -0700 10) #include "delta.h" a733cb60 (Linus Torvalds 2005-06-28 14:21:02 -0700 11) #include "pack.h" 8e440259 (Peter Eriksen 2006-04-02 14:44:09 +0200 12) #include "blob.h" 8e440259 (Peter Eriksen 2006-04-02 14:44:09 +0200 13) #include "commit.h" 8e440259 (Peter Eriksen 2006-04-02 14:44:09 +0200 14) #include "tag.h" 8e440259 (Peter Eriksen 2006-04-02 14:44:09 +0200 15) #include "tree.h" f35a6d3b (Linus Torvalds 2007-04-09 21:20:29 -0700 16) #include "refs.h" 70f5d5d3 (Nicolas Pitre 2008-02-28 00:25:19 -0500 17) #include "pack-revindex.h"628522ec (Junio C Hamano 2007-12-29 02:05:47 -0800 18) #include "sha1-lookup.h" . 

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

Вы также можете определить для этой команды начальную и конечную строки:

$>git blame -L 160,+10 sha1_file.c ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700 160)> ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700 161) 0fcfd160 (Linus Torvalds 2005-04-18 13:04:43 -0700 162)/* 0fcfd160 (Linus Torvalds 2005-04-18 13:04:43 -0700 163) * NOTE! This returns a statically allocate 790296fd (Jim Meyering 2008-01-03 15:18:07 +0100 164) * careful about using it. Do an "xstrdup() 0fcfd160 (Linus Torvalds 2005-04-18 13:04:43 -0700 165) * filename. ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700 166) * ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700 167) * Also note that this returns the location ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700 168) * SHA1 file can happen from any alternate d19938ab (Junio C Hamano 2005-05-09 17:57:56 -0700 169) * DB_ENVIRONMENT environment variable if i 

This book is maintained by Scott Chacon, and hosting is donated by GitHub.
Please email me at schacon@gmail.com with patches, suggestions and comments.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *