Git
Chapters ▾ 2nd Edition

7.10 Orodja Git - Razhroščevanje z Gitom

Razhroščevanje z Gitom

Poleg osnovne uporabe kot sistem za nadzor različic ima Git na voljo tudi nekaj ukazov, ki pomagajo pri iskanju napak v vaših projektih s programsko kodo. Ker je Git zasnovan za upravljanje skoraj vsake vrste vsebine, so ta orodja precej splošna, vendar vam lahko pogosto pomagajo pri iskanju napake ali krivca, ko se stvari pokvarijo.

Anotacija datotek

Če odkrijete napako v svojem kodiranju in želite vedeti, kdaj in zakaj je bila uvedena, je anotacija datoteke pogosto vaše najboljše orodje. Prikaže vam, katera potrditev je bila zadnja, ki je spremenila vsako vrstico v kateri koli datoteki. Če opazite, da je metoda v vašem kodiranju napačna, lahko z anotacijo datoteke z git blame tako ugotovite, katera potrditev je bila odgovorna za uvedbo te vrstice.

V spodnjem primeru git blame določa, katera potrditev in avtor sta bila odgovorna za vrstice v glavnem jedru Linux datoteke Makefile, in še dodatno uporablja možnost -L, da omeji izpis anotacije na vrstice od 69 do 82 v tej datoteki:

$ 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

Opazite, da je prvo polje delni zapis SHA-1 potrditve, ki je zadnja spremenila to vrstico. Naslednji dve polji sta vrednosti, ki sta izvlečeni iz te potrditve — ime avtorja in časovno obdobje, ko je bila ta potrditev spremenjena — tako da lahko enostavno vidite, kdo in kdaj je spremenil to vrstico. Nato sledita številka vrstice in vsebina datoteke. Opazite tudi vrstice, ki se začnejo z ^1da177e4c3f4 — predpona ^ označuje vrstice, ki so bile uvedene v prvotni potrditvi repozitorija in so ostale nespremenjene vse od takrat. To je nekoliko zmedeno, saj ste zdaj videli vsaj tri različne načine, kako Git uporablja ^ za spreminjanje SHA-1 potrditev, vendar to tukaj to pomeni.

Še ena dobra stvar pri Gitu je, da ne sledi preimenovanju datotek eksplicitno. Namesto tega beleži posnetke in poskuša ugotoviti, kaj je bilo v resnici implicitno preimenovano. Ena od zanimivih lastnosti tega je, da lahko zaprosite, naj ugotovi vse vrste premikov kode. Če git blame podate -C, Git analizira datoteko, ki jo označujete, in poskuša ugotoviti, od kod so bili kopirani posamezni odseki kode, če so bili kopirani iz drugega kraja. Na primer, recimo, da preoblikujete datoteko imenovano GITServerHandler.m v več datotek, ena izmed njih pa je GITPackUpload.m. S pomočjo možnosti -C lahko označite GITPackUpload.m in vidite, od kod so bili prvotno vzeti odseki kode:

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

To je resnično koristno. Običajno kot izvorno potrditev dobite potrditev, kjer ste prekopirali kodo, ker ste se prvič dotaknili teh vrstic v tej datoteki. Git vam pove, katera potrditev je izvorno vsebovala te vrstice, tudi če je bilo to v drugi datoteki.

Anotiranje datoteke je uporabno, če veste, kje je sploh težava. Če ne veste, kaj se je pokvarilo, in je bilo narejenih na desetine ali stotine potrditev od zadnjega stanja, kjer ste vedeli, da vaša koda deluje, se boste za pomoč verjetno obrnili na git bisect. Ukaz bisect opravi dvojiško iskanje skozi vašo zgodovino potrditev, da vam pomaga čim hitreje ugotoviti, katera potrditev je uvedla težavo.

Recimo, da ste pravkar izdali različico svoje kode v produkcijsko okolje, prejemate pa poročila o napaki, ki se ni pojavljala v razvojnem okolju, in ne morete ugotoviti, zakaj se koda obnaša tako. Vrnili ste se k svoji kodi in ugotovite, da lahko reproducirate težavo, vendar ne morete ugotoviti, kaj gre narobe. Za ugotavljanje vzroka težave lahko uporabite razpolovitev. Najprej zaženete git bisect start, da začnete postopek, nato pa uporabite git bisect bad, da sistemu sporočite, da je trenutna potrditev pokvarjena. Nato morate ukazu bisect z uporabo git bisect good <good_commit> povedati, kdaj je bilo nazadnje znano dobro stanje:

$ 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 je ugotovil, da je bilo med zaznamkom zadnje dobre potrditve (v1.0) in trenutno slabo različico približno 12 potrditev in izbral vam je srednjo potrditev. Trenutno lahko zaženete svoj test in preverite, ali obstaja težava v tej potrditvi. Če težava obstaja, je bila uvedena pred to srednjo potrditvijo; če ne obstaja, je bila težava uvedena po tej srednji potrditvi. Izkazalo se je, da v tem stanju ni težave, zato to sporočite Gitu s pomočjo git bisect good in nadaljujete svojo pot:

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

Zdaj ste na drugi potrditvi, na pol poti med tisto, ki ste jo pravkar preverili, in svojo slabo potrditvijo. Znova zaženete svoj test in ugotovite, da je ta potrditev pokvarjena, zato to sporočite Gitu s pomočjo git bisect bad:

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

Ta potrditev je v redu in zdaj ima Git vse informacije, ki jih potrebuje, da ugotovi, kje je bil vnesen problem. Pove vam SHA-1 prve slabe potrditve in prikaže nekatere informacije o potrditvi ter katere datoteke so bile spremenjene v tej potrditvi, tako da lahko ugotovite, kaj se je zgodilo, da bi lahko uvedlo to napako:

$ 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

Ko končate, morate za ponastavitev svoje glave (HEAD) na stanje, v katerem ste bili pred začetkom, zagnati ukaz git bisect reset, sicer boste ostali v čudnem stanju:

$ git bisect reset

To je zmogljivo orodje, ki vam lahko v nekaj minutah pomaga preveriti na stotine potrditev za napako, ki je bila vnesena. Pravzaprav, če imate skript, ki se bo zaključil z 0, če je projekt v redu, ali neničelno vrednostjo, če je projekt slab, lahko git bisect v celoti izvedete samodejno. Najprej mu spet sporočite obseg ukaza bisect tako, da podate znane slabe in dobre potrditve. To lahko storite tako, da jih navedete z ukazom bisect start, če želite, tako da najprej navedete znano slabo potrditev, drugo znano dobro potrditev pa drugo:

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

S tem bo Git samodejno izvedel test-error.sh na vsaki izvlečeni potrditvi, dokler ne najde prve napačne. Lahko pa uporabite tudi make, make tests, ali karkoli že imate za izvedbo avtomatskih testov.

scroll-to-top