Git
Chapters ▾ 2nd Edition

7.1 Orodja Git - Izbira revizije

Do sedaj ste se naučili večine vsakodnevnih ukazov in potekov dela, ki jih potrebujete za upravljanje ali vzdrževanje repozitorija Git za svoj nadzor izvorne kode. Opravili ste osnovna opravila sledenja in potrjevanja datotek ter oprti ste z zmogljivostjo področja priprave in enostavnega tematskega razvejanja in združevanja.

Sedaj boste raziskali vrsto zelo zmogljivih stvari, ki jih lahko naredi Git, in lahko jih morda ne nujno uporabljali vsak dan, vendar jih boste morda kdaj potrebovali.

Izbira revizije

Git vam omogoča, da se sklicujete na eno samo potrditev, niz potrditev, ali obseg potrditev na več načinov. Niso nujno očitni, vendar je koristno vedeti zanje.

Posamezne revizije

Očitno lahko navedete katerokoli posamezno potrditev po celotni 40-znakovni zgoščeni vrednosti SHA-1, vendar obstajajo načini, ki so bolj prijazni do uporabnikov. V tem razdelku so opisani različni načini, kako se lahko sklicujete na katerokoli potrditev.

Kratek SHA-1

Git je dovolj pameten, da ugotovi, katero potrditev mislite, če navedete prvih nekaj znakov zgoščene vrednosti SHA-1, če je ta delna zgoščena vrednost dolga vsaj štiri znake in je nedvoumna; to pomeni, da noben drug objekt v objektni bazi podatkov ne more imeti zgoščene vrednosti, ki se začne z enako predpono.

Na primer, da bi preučili določeno potrditev, kjer veste, da ste dodali določeno funkcionalnost, bi najprej pognali ukaz git log, da bi našli to potrditev:

$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jan 2 18:32:33 2009 -0800

    Fix refs handling, add gc auto, update tests

commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'

commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 14:58:32 2008 -0800

    Add some blame and merge stuff

V tem primeru recimo, da vas zanima potrditev, katere zgoščena vrednost se začne z 1c002dd…​. To potrditev lahko pregledate z uporabo katere koli od naslednjih različic git show (ob predpostavki, da so krajše različice nedvoumne):

$ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
$ git show 1c002dd4b536e7479f
$ git show 1c002d

Git lahko ugotovi kratko in edinstveno okrajšavo za vaše vrednosti SHA-1. Če podate --abbrev-commit ukazu git log, bo izhod uporabljal krajše vrednosti, vendar jih bo še vedno obdržal edinstvene; privzeto uporablja sedem znakov, vendar jih bo podaljšal, če je to potrebno, da ohrani edinstvenost SHA-1:

$ git log --abbrev-commit --pretty=oneline
ca82a6d Change the version number
085bb3b Remove unnecessary test code
a11bef0 Initial commit

Na splošno je osem do deset znakov več kot dovolj, da so edinstveni v okviru projekta. Na primer, do februarja 2019 je imelo jedro Linux (ki je precej obsežen projekt) več kot 875.000 potrditev in skoraj sedem milijonov objektov v svoji objektni podatkovni bazi, pri čemer ni dveh objektov, ki bi imela enaki vrednosti SHA-1 v prvih 12 znakih.

Opomba
KRATKA OPOMBA O SHA-1

Veliko ljudi na neki točki začne skrbeti, da bodo zaradi naključnih okoliščin imeli v svojem repozitoriju dva različna objekta, ki se preslikata v enako zgoščeno vrednost SHA-1. Kaj potem?

Če naključno ustvarite objekt, ki se preslika v enako zgoščeno vrednost SHA-1 kot obstoječi objekt v vašem repozitoriju, bo Git v vaši bazi podatkov Git videl že obstoječi objekt, predvideval, da je bil že napisan in ga preprosto ponovno uporabil. Če poskušate ta objekt kadarkoli znova izpisati, boste vedno dobili podatke prvega objekta.

Vendar morate biti pozorni na to, kako izredno malo verjeten je ta scenarij. Odtis SHA-1 je sestavljen iz 20 bajtov oziroma 160 bitov. Število naključno zgoščenih objektov, ki jih potrebujete, da zagotovite 50-odstotno verjetnost enega samega trčenja, je približno 280 (formula za določanje verjetnosti trčenja je p = (n(n-1)/2) * (1/2^160)). 280 je 1,2 x 1024 ali 1 milijon milijard milijard. To je 1.200-krat večje od števila zrn peska na Zemlji.

Tukaj je primer, da si predstavljate, kaj bi bilo potrebno, da bi prišlo do trčenja SHA-1. Če bi vseh 6,5 milijarde ljudi na Zemlji programiralo in vsako sekundo vsak od njih ustvaril kodo, ki bi bila enakovredna celotni zgodovini jedra Linuxa (6,5 milijona objektov Git), in jo potisnilo v en ogromen repozitorij Git, bi trajalo približno 2 leti, da bi se v tem repozitoriju nahajalo dovolj objektov za 50-odstotno verjetnost enega samega trčenja objekta SHA-1. Zato je organsko trčenje SHA-1 manj verjetno, kot da bi vsakega člana vaše programerske ekipe napadli in ubili volkovi v nepovezanih incidentih iste noči.

Če namenite več tisoč dolarjev računalniške moči, je mogoče sintetizirati dve datoteki z enako zgoščeno vrednostjo, kar je bilo dokazano na spletnem mestu https://shattered.io/ februarja 2017. Git se premika v smeri uporabe SHA256 kot privzetega algoritma za zgoščene vrednosti, kar je veliko bolj odporno proti napadom z zrušitvijo, in ima kodo, ki pomaga omiliti ta napad (čeprav ga ne more popolnoma odpraviti).

Reference vej

Enostaven način za sklicevanje na določeno potrditev je, če je ta potrditev na vrhu veje; v tem primeru lahko v katerem koli ukazu Git, ki pričakuje sklicevanje na potrditev, uporabite ime veje. Na primer, če želite preučiti zadnji objekt potrditve v veji, sta naslednja ukaza enakovredna, če privzamemo, da se veja topic1 sklicuje na potrditev ca82a6d…​:

$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1

Če želite videti, na kateri specifični SHA-1 se nanaša veja, ali če želite videti, kaj kateri od teh primerov pomeni v smislu SHA-1, lahko uporabite Gitovo orodje napeljave imenovano rev-parse. Za več informacij o orodjih napeljave si oglejte poglavje Notranjost Gita; v osnovi obstaja orodje rev-parse za nižje nivojske operacije in ni zasnovano za vsakodnevno uporabo. Vendar pa je včasih lahko koristno, ko želite videti, kaj se v resnici dogaja. Tukaj lahko poženete rev-parse na svoji veji.

$ git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949

Kratka imena reflog

Ena od stvari, ki jih Git počne v ozadju med vašim delom, je ohranjanje »refloga« — dnevnika, kjer so shranjene informacije o tem, kje so bili vaš HEAD in reference vej v zadnjih nekaj mesecih.

Svoj reflog lahko vidite z uporabo git reflog:

$ git reflog
734713b HEAD@{0}: commit: Fix refs handling, add gc auto, update tests
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by the 'recursive' strategy.
1c002dd HEAD@{2}: commit: Add some blame and merge stuff
1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
95df984 HEAD@{4}: commit: # This is a combination of two commits.
1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD

Vsakič, ko se iz kakršnega koli razloga vaš vrh veje posodobi, Git shrani to informacijo v začasno zgodovino. Svoje podatke refloga lahko uporabite tudi za sklicevanje na starejše potrditve. Na primer, če želite videti peto predhodno vrednost HEAD vašega repozitorija, lahko uporabite referenco @{5}, ki jo vidite v izpisu refloga:

$ git show HEAD@{5}

To sintakso lahko uporabite tudi za ogled, kje je bila veja pred določenim časom. Na primer, da bi videli, kje je bila vaša veja master včeraj, lahko vnesete:

$ git show master@{yesterday}

To bi vam pokazalo, kje je bil vrh vaše veje master včeraj. Ta tehnika deluje samo za podatke, ki so še vedno v vašem reflogu, zato je ne morete uporabiti za iskanje potrditev, starejših od nekaj mesecev.

Če želite videti informacije refloga oblikovane kot izpis git log, lahko zaženete git log -g:

$ git log -g master
commit 734713bc047d87bf7eac9674765ae793478c50d3
Reflog: master@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: commit: Fix refs handling, add gc auto, update tests
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jan 2 18:32:33 2009 -0800

    Fix refs handling, add gc auto, update tests

commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Reflog: master@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: merge phedders/rdocs: Merge made by recursive.
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'

Pomembno je opozoriti, da so informacije o reflogu izključno lokalne — gre le za dnevnik tega, kar ste vi storili v vašem repozitoriju. Reference ne bodo enake na kopiji repozitorija nekoga drugega; tudi takoj po prvotnem kloniranju repozitorija boste imeli prazen reflog, saj se v vašem repozitoriju še ni zgodila nobena dejavnost. Če zaženete git show HEAD@{2.months.ago}, vam bo ujemajoča se potrditev prikazana samo, če ste projekt klonirali vsaj pred dvema mesecema — če ste ga klonirali še bolj nedavno, boste videli samo svojo prvo lokalno potrditev.

Namig
Predstavljajte si reflog kot Gitovo različico zgodovine lupin

Če imate ozadje z Unix ali Linux, lahko reflog v Gitu razumete kot različico zgodovine ukazov lupine, kar poudarja, da je vse v njej pomembno samo za vas in vašo »sejo« in nima nobene zveze z drugimi, ki morda delajo na istem računalniku.

Opomba
Ubežanje oklepajev v PowerShellu

Pri uporabi PowerShella so zaviti oklepaji, kot sta { in }, posebni znaki in jih je treba ubežati. Ubežite jih lahko z levo črtico ` ali pa daste referenco na potrditev v narekovaje:

$ git show HEAD@{0}     # will NOT work
$ git show HEAD@`{0`}   # OK
$ git show "HEAD@{0}"   # OK

Reference prednikov

Drugi glavni način za določitev potrditve je prek njenega prednika. Če na koncu reference dodate ^ (karet), Git razume, da to pomeni nadrejeno te potrditve. Recimo, da pogledate zgodovino svojega projekta:

$ git log --pretty=format:'%h %s' --graph
* 734713b Fix refs handling, add gc auto, update tests
*   d921970 Merge commit 'phedders/rdocs'
|\
| * 35cfb2b Some rdoc changes
* | 1c002dd Add some blame and merge stuff
|/
* 1c36188 Ignore *.gem
* 9b29157 Add open3_detach to gemspec file list

Nato lahko vidite prejšnjo potrditev z določitvijo HEAD^, kar pomeni »nadrejena od HEAD«:

$ git show HEAD^
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'
Opomba
Ubežanje znaka karet na sistemu Windows

Na sistemu Windows se ^ v cmd.exe obravnava kot poseben znak in ga je treba obravnavati drugače. Lahko ga podvojite ali pa postavite referenco potrditve v narekovaje:

$ git show HEAD^     # will NOT work on Windows
$ git show HEAD^^    # OK
$ git show "HEAD^"   # OK

Za ^ lahko navedete tudi številko, da identificirate, katero nadrejeno želite; na primer, d921970^2 pomeni »druga nadrejena d921970«. Ta sintaksa je uporabna le za potrditve združitev, ki imajo več kot eno nadrejeno — prva nadrejena od potrditve združitve je iz veje, na kateri ste bili, ko ste opravili združitev (pogosto master), medtem ko je druga nadrejena od potrditve združitve iz veje, ki je bila združena (recimo topic):

$ git show d921970^
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 14:58:32 2008 -0800

    Add some blame and merge stuff

$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
Author: Paul Hedderly <paul+git@mjr.org>
Date:   Wed Dec 10 22:22:03 2008 +0000

    Some rdoc changes

Druga glavna specifikacija prednikov je ~ (vijuga). Ta se prav tako nanaša na prvo nadrejeno, zato sta HEAD~ in HEAD^ enakovredna. Razlika postane očitna, ko navedete število. HEAD~2 pomeni »prvo nadrejeno od prve nadrejene« — skozi prve nadrejene gre tolikokrat, kolikor je navedeno število. Na primer, v prej omenjeni zgodovini bi bil HEAD~3:

$ git show HEAD~3
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date:   Fri Nov 7 13:47:59 2008 -0500

    Ignore *.gem

To se lahko napiše tudi kot HEAD~~~, kar je ponovno prva nadrejena prve nadrejene od prve nadrejene.

$ git show HEAD~~~
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date:   Fri Nov 7 13:47:59 2008 -0500

    Ignore *.gem

Te sintakse lahko tudi kombinirate — dobite lahko drugo nadrejeno od prejšnje reference (ob predpostavki, da je šlo za potrditev združitve) z uporabo HEAD~3^2 itn.

Obsegi potrditev

Zdaj, ko lahko navedete posamezne potrditve, poglejmo, kako določiti obsege potrditev. To je še posebej koristno za upravljanje vej — če imate veliko vej, lahko z uporabo obsega potrditev odgovorite na vprašanja, kot so, »Kakšno delo je na tej veji, ki ga še nisem združil v svojo glavno vejo?«

Dvojna pika

Najpogostejša specifikacija obsega je sintaksa z dvema pikama. To Gitu omogoča, da določi obseg potrditev, ki so dosegljive iz ene potrditve, a niso dosegljive iz druge. Na primer, recimo, da imate zgodovino potrditev, ki je videti kot slika Primer zgodovine za izbiro obsega.

Primer zgodovine za izbiro obsega
Slika 136. Primer zgodovine za izbiro obsega

Recimo, da želite videti, kaj je v vaši veji experiment, ki še ni združena v vašo vejo master. Z Gitom lahko zaprosite, da vam prikaže dnevnik samo teh potrditev z master..experiment — to pomeni »vse potrditve, ki so dostopne iz experiment in niso dostopne iz master«. V teh primerih sta zaradi kratkosti in jasnosti uporabljeni črki objektov potrditev iz diagrama namesto dejanskega zapisa dnevnika v vrstnem redu, kot bi se prikazali:

$ git log master..experiment
D
C

Če pa želite videti nasprotno — vse potrditve v veji master, ki niso v veji experiment, lahko imena vej obrnete. experiment..master vam pokaže vse, kar je v master in ni dosegljivo iz veje experiment:

$ git log experiment..master
F
E

To je uporabno, če želite imeti vejo experiment posodobljeno in si ogledati, kaj boste združili. Še en pogost način uporabe te sintakse je ogled tega, kar boste potisnili na oddaljeni strežnik:

$ git log origin/master..HEAD

Ta ukaz vam prikaže vse potrditve na trenutni veji, ki niso na veji master vašega oddaljenega repozitorija origin. Če zaženete git push in vaša trenutna veja sledi origin/master, bodo potrditve, navedene iz git log origin/master..HEAD, potrditve, ki bodo prenesene na strežnik. Eno stran sintakse lahko tudi izpustite, da Git uporabi HEAD. Na primer, dobite lahko enake rezultate kot v prejšnjem primeru, tako da vnesete git log origin/master.. — Git nadomesti HEAD, če ena stran manjka.

Več točk

Sintaksa z dvojno piko (angl. double-dot) je uporabna kot bližnjica, vendar morda želite navesti več kot dve veji, da določite svojo revizijo, na primer, videti želite, katera izmed več vej je vsebovala zadnje potrditve, ki še niso vključene v vašo trenutno vejo. Git vam to omogoča s pomočjo znaka ^ ali --not pred katerim koli referenčnim naslovom, od katerega naprej ne želite videti dosegljivih sprememb. Tako so naslednji trije ukazi enakovredni:

$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refA

To je dobro, saj s to sintakso lahko v svojem poizvedovanju določite več kot dva sklica, kar ni mogoče z dvojno piko. Na primer, če želite videti vse potrditve, do katerih je mogoče dostopati iz refA ali refB, vendar ne iz refC, lahko uporabite katero koli od teh možnosti:

$ git log refA refB ^refC
$ git log refA refB --not refC

To je zelo zmogljiv sistem za poizvedovanje v zgodovini revizij, ki vam bo pomagal ugotoviti, kaj je v vaših vejah.

Trojna pika

Zadnja glavna sintaksa za izbiro obsega je trojna pika, ki določa vse potrditve, do katerih je mogoče priti bodisi z eno ali drugo referenco, ne pa z obema hkrati. Oglejmo si primer zgodovine potrditev na sliki Primer zgodovine za izbiro obsega. Če želite videti, kaj je v master ali experiment vendar brez skupnih referenc, lahko poženete:

$ git log master...experiment
F
E
D
C

Spet dobite običajen izpis log, vendar vam prikaže samo informacije o potrditvah za te štiri potrditve, ki se pojavijo v tradicionalnem zaporedju datumov potrditev.

Pogost preklop, ki se uporablja skupaj z ukazom log v tem primeru, je --left-right, ki vam pokaže, na kateri strani obsega je posamezna potrditev. To pomaga, da je izpis bolj uporaben:

$ git log --left-right master...experiment
< F
< E
> D
> C

S temi orodji lahko veliko enostavneje sporočite Gitu, katero potrditev ali več njih želite pregledati.

scroll-to-top