Git
Chapters ▾ 2nd Edition

7.10 Гит алати - Отклањање грешака са програмом Git

Отклањање грешака са програмом Git

Програм Гит такође обезбеђује и неколико алата који помажу при отклањању проблема у вашим пројектима. Пошто је програм Гит дизајниран тако да ради са скоро било којом врстом пројекта, ови алати су прилично општи, али вам често могу помоћи да уловите баг или кривца када ствари крену низбрдо.

Означавање фајла

Ако пратите баг у свом коду и желите да сазнате када је уведен и зашто, означавање фајла вам је најчешће најбољи алат. Ознаке показују који комит је последњи изменио сваку линију било ког фајла. Дакле, ако приметите да метода у коду има багове, фајл можете да означите напоменама командом git blame и да одредите који комит је одговоран за увођење те линије.

У следећем примеру се користи git blame да се одреди који комит и аутор је одговоран за линије у Makefile највишег нивоа Линукс кернела, а такође користи и опцију -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 контролне суме комита који је последњи изменио ту линију. Наредна два поља су вредности издвојене из тог комита –- име аутора и датум настанка тог комита – тако да лако можете видети ко је изменио ту линију и када. Након тога долазе број линије и садржај фајла. Такође приметите ^1da177e4c3f4 комит линије, у којима префикс ^ означава линије које су уведене у репозиторијумов почетни комит и од тада су остале непромењене. Ово уноси поприличну забуну јер сте до сада видели барем три различита начина на које програм Гит користи ^ за измену SHA-1 комита, али то је значење овде.

Још једна одлична ствар у вези програма Гит је да он експлицитно не прати имена фајлова. Он чува снимке и онда покушава да одреди чему је имплицитно промењено име, након што се то већ догодило. Једна од интересантних могућности овога је да од програма можете тражити и да открије разноразна померања кода. Ако команди git blame проследите опцију -C, програм Git анализира фајл који означавате и покушава да открије одакле су дошли сегменти кода у случају да су били ископирани са неког другог места. На пример, рецимо да рефакторишете фајл под именом GITServerHandler.m у више фајлова, од којих је један GITPackUpload.m. Окривљујући (blaming — оригинално значење команде, прим. прев.) GITPackUpload.m уз опцију -C, видећете одакле су потекли делови кода:

$ 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 bisect за помоћ. Команда bisect врши бинарну претрагу кроз историју ваших комитова како бисте што брже пронашли комит који је увео проблем.

Рецимо да сте управо објавили издање свог кода на производном окружењу, па добијате извештаје о багу који наводе да се нешто у производном окружењу не дешава, а ви не можете да замислите зашто се кôд тако понаша. Враћате се на свој кôд и испоставља се да можете поново изазвати проблем, али нема шансе да откријете шта не ваља. Да бисте открили, можете да извршите бисекцију кода. Најпре извршите git bisect start да покренете ствари, па затим употребите git bisect bad да систему кажете да је комит на којем се тренутно налазите неисправан. Затим, помоћу git bisect good [исправан_комит] бисекцији морате навести последње познато исправно стање:

$ 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 bisect good, па настављате своје путовање:

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

Сада сте на још једном комиту, на пола пута између онога који сте тестирали и вашег неисправног комита. Поново покрећете свој тест и откривате да је овај комит неисправан, па то саопштавате програму Гит са git bisect bad:

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

Овај комит је у реду, а програм Гит сада има све информације потребне да одреди место на којем је уведен проблем. Наводи вам SHA-1 суму првог неисправног комита и приказује неке од комит информација, као и фајлове који су измењени у том комиту, тако да можете одредити шта се догодило и увело овај баг:

$ git bisect good
b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <pjhyett@example.com>
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 ако је пројекат добар, или нешто различито од 0 ако није, git bisect можете потпуно аутоматизовати. Најпре, поново наводите опсег бисекције задајући познате неисправне и исправне комитове. То можете урадити наводећи их у команди bisect start ако желите, тако што прво иде познати неисправан комит, па затим познати исправан комит:

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

Када ово покренете, test-error.sh се аутоматски извршава након сваког одјављеног комита све док програм Гит не пронађе први неисправан комит. Такође можете да извршите нешто као што је make или make tests или штагод имате да уместо вас покреће аутоматизоване тестове.