Chapters ▾ 2nd Edition

7.10 Git Tools - Ontfouting met Git (Debugging with Git)

Ontfouting met Git (Debugging with Git)

Benewens dat dit hoofsaaklik vir weergawebeheer is, bied Git ook 'n paar opdragte om jou te help om jou bronkodeprojekte te ontfout (debug). Omdat Git ontwerp is om byna enige tipe inhoud te hanteer, is hierdie instrumente redelik generies, maar hulle kan jou dikwels help om vir 'n fout (bug) of skuldige te jag wanneer dinge skeefloop.

Lêer-annotasie (File Annotation)

As jy 'n fout in jou kode opspoor en wil weet wanneer dit ingestel is en hoekom, is lêer-annotasie dikwels jou beste instrument. Dit wys jou watter vaslegging (commit) die laaste was om elke reël van enige lêer te wysig. So as jy sien dat 'n metode in jou kode foutief (buggy) is, kan jy die lêer annoteer met git blame om te bepaal watter vaslegging verantwoordelik was vir die instelling van daardie reël.

Die volgende voorbeeld gebruik git blame om te bepaal watter vaslegging en vaslêer (committer) verantwoordelik was vir reëls in die boonste vlak (top-level) Linux-kern Makefile en gebruik verder die -L opsie om die afvoer van die annotasie tot reëls 69 tot 82 van daardie lêer te beperk:

$ 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

Let op dat die eerste veld die gedeeltelike SHA-1 is van die vaslegging wat daardie reël laas gewysig het. Die volgende twee velde is waardes onttrek uit daardie vaslegging — die outeurnaam en die outeursdatum van daardie vaslegging — sodat jy maklik kan sien wie daardie reël gewysig het en wanneer. Daarna kom die reëlnommer en die inhoud van die lêer. Let ook op die ^1da177e4c3f4 vasleggingsreëls, waar die ^ voorvoegsel reëls aandui wat in die bewaarplek se aanvanklike vaslegging ingestel is en sedertdien onveranderd gebly het. Dit is 'n bietjie verwarrend, want nou het jy al ten minste drie verskillende maniere gesien waarop Git die ^ gebruik om 'n vaslegging SHA-1 te wysig, maar dit is wat dit hier beteken.

Nog 'n oulike ding van Git is dat dit nie lêerhernoemings eksplisiet naspoor nie. Dit neem die momentopnames (snapshots) op en probeer dan uitvind wat implisiet hernoem is, na die tyd. Een van die interessante kenmerke hiervan is dat jy dit kan vra om ook allerhande kodebewegings uit te vind. As jy -C na git blame aangee, ontleed Git die lêer wat jy annoteer en probeer uitvind waar brokkies kode daarin oorspronklik vandaan kom as dit van iewers anders gekopieer is. Sê byvoorbeeld jy is besig om 'n lêer genaamd GITServerHandler.m in verskeie lêers te herstruktureer (refactor), waarvan een GITPackUpload.m is. Deur GITPackUpload.m te blame met die -C opsie, kan jy sien waar gedeeltes van die kode oorspronklik vandaan kom:

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

Dit is regtig nuttig. Normaalweg kry jy as die oorspronklike vaslegging die vaslegging waar jy die kode oorgekopieer het, want dit is die eerste keer dat jy aan daardie reëls in hierdie lêer geraak het. Git vertel jou die oorspronklike vaslegging waar jy daardie reëls geskryf het, selfs al was dit in 'n ander lêer.

Die annotasie van 'n lêer help as jy weet waar die kwessie is om mee te begin. As jy nie weet wat breek nie, en daar was dosyne of honderde vasleggings sedert die laaste toestand waar jy weet die kode gewerk het, sal jy waarskynlik na git bisect wend vir hulp. Die bisect opdrag doen 'n binêre soektog deur jou vasleggingsgeskiedenis om jou te help om so vinnig as moontlik te identifiseer watter vaslegging 'n kwessie ingestel het.

Sê nou jy het pas 'n vrystelling (release) van jou kode na 'n produksie-omgewing gepush, jy kry foutverslae (bug reports) oor iets wat nie in jou ontwikkelingsomgewing gebeur het nie, en jy kan nie dink hoekom die kode dit doen nie. Jy gaan terug na jou kode, en dit blyk dat jy die kwessie kan reproduseer, maar jy kan nie uitvind wat verkeerd loop nie. Jy kan die kode halveer (bisect) om uit te vind. Eerstens voer jy git bisect start uit om dinge aan die gang te kry, en dan gebruik jy git bisect bad om vir die stelsel te sê dat die huidige vaslegging waarop jy is, gebreek is. Dan moet jy vir bisect sê wanneer die laaste bekende goeie toestand was, met behulp van 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 het uitgevind dat ongeveer 12 vasleggings gekom het tussen die vaslegging wat jy as die laaste goeie vaslegging (v1.0) gemerk het en die huidige slegte weergawe, en dit het die middelste een vir jou uitgetrek (checked out). Op hierdie punt kan jy jou toets uitvoer om te sien of die kwessie by hierdie vaslegging bestaan. As dit wel die geval is, dan is dit iewers voor hierdie middelste vaslegging ingestel; as dit nie is nie, dan is die probleem iewers ná die middelste vaslegging ingestel. Dit blyk daar is geen kwessie hier nie, en jy vertel Git dit deur git bisect good te tik en sit jou reis voort:

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

Nou is jy op 'n ander vaslegging, halfpad tussen die een wat jy pas getoets het en jou slegte vaslegging. Jy voer jou toets weer uit en vind dat hierdie vaslegging gebreek is, so jy sê dit vir Git met git bisect bad:

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

Hierdie vaslegging is reg, en nou het Git al die inligting wat dit nodig het om te bepaal waar die kwessie ingestel is. Dit vertel jou die SHA-1 van die eerste slegte vaslegging en wys van die vasleggingsinligting en watter lêers in daardie vaslegging gewysig is sodat jy kan uitvind wat gebeur het wat moontlik hierdie fout ingestel het:

$ 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

Wanneer jy klaar is, moet jy git bisect reset uitvoer om jou HEAD terug te stel na waar jy was voor jy begin het, of jy sal in 'n vreemde toestand eindig:

$ git bisect reset

Dit is 'n kragtige instrument wat jou kan help om honderde vasleggings in minute vir 'n ingestelde fout na te gaan. Trouens, as jy 'n skrip het wat 0 sal afsluit (exit) as die projek goed is of nie-0 as die projek sleg is, kan jy git bisect ten volle outomatiseer. Eerstens vertel jy dit weer die omvang (scope) van die halvering (bisect) deur die bekende slegte en goeie vasleggings te verskaf. Jy kan dit doen deur hulle met die bisect start opdrag te lys as jy wil, deur die bekende slegte vaslegging eerste en die bekende goeie vaslegging tweede te lys:

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

Deur dit te doen, word test-error.sh outomaties op elke uitgetrekte (checked-out) vaslegging uitgevoer totdat Git die eerste gebreekte vaslegging vind. Jy kan ook iets soos make of make tests uitvoer, of wat jy ook al het wat geoutomatiseerde toetse vir jou uitvoer.