Git
Chapters ▾ 2nd Edition

7.1 Гит алати - Избор ревизија

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

Сада ћете истражити више веома моћних ствари које програм Гит може да уради, а које вероватно нећете свакодневно користити. Али у неком тренутку ће вам бити потребне.

Избор ревизија

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

Просте ревизије

Један комит очигледно можете да наведете његовом пуном SHA-1 контролном сумом дужине 40 карактера, али такође постоје и начини навођења комитова који су лакши за људе. Овај одељак представља различите начине на које можете навести један комит.

Кратак SHA-1

Програм Гит је довољно паметан да одреди на који комит мислите када откуцате неколико првих карактера, све док је делимичан SHA-1 дужине барем четири карактера и није двосмислен – то јест, само један објекат у текућем репозиторијуму почиње тим делимичним SHA-1.

На пример, ако желите да погледате један комит, претпоставимо да извршите команду git log и пронађете комит у којем сте додали одређену функционалност:

$ 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

У овом случају, рецимо да се заинтересовани за комит чији хеш почиње са 1c002dd…​. Тај комит можете да испитате било којом од следећих варијација комаде git show (под претпоставком да су краће верзије недвосмислене):

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

Програм Гит може да одреди кратку, јединствену скраћеницу ваших SHA-1 вредности. Ако команди git log проследите --abbrev-commit, излаз ће приказати краће вредности, али ће остати јединствене; подразумевано користи седам карактера, али ако је потребно да се одржи недвосмисленост SHA-1 биће дужи:

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

У општем случају, осам до десет карактера је више него довољно да буде јединствено у оквиру пројекта. На пример, у фебруару 2019, Линукс кернел (који је прилично стабилан пројекат) у својој бази података објеката име преко 875.000 комитова и скоро седам милиона објеката, а не постоје објекти чије су SHA-1 контролне суме идентичне у првих 12 карактера.

Белешка
КРАТКА НАПОМЕНА У ВЕЗИ SHA-1

Доста људи је у неком тренутку постало забринуто да ће, неким случајем, имати у свом репозиторијуму два различита објекта који имају исту SHA-1 контролну суму. Шта онда?

Ако се деси да комитујете објекат чија је SHA-1 вредност контролне суме иста као неког ранијег различитог објекта у вашем репозиторијуму, програм Гит ће видети претходни објекат који се већ налази у бази података, претпоставиће да је већ уписан и једноставно ће да поново искористити. Ако у неком тренутку покушате да одјавите так објекат, увек ћете добити податке из првог објекта.

Међутим, требало би да сте свесни колико је невероватно мала вероватноћа оваквог сценарија. The SHA-1 хеш је дужине 20 бајтова или 160 битова. Број насумично хешираних објеката који су потребни да се обезбеди 50% вероватноће једне једине колизије је око 280 (формула за одређивање вероватноће колизије је p = (n(n-1)/2) * (1/2^160)). 280 је 1,2 x 1024 или 1 милион милијарди милијади. То је 1.200 пута веће од укупног броја свих зрнаца песка на планети Земљи.

Ево примера који вам даје идеју шта би требало да се догоди па да дође до SHA-1 колизије. Ако би свих 6,5 милијарди људи на Земљи програмирало и сваке секунде, свако од њих генерише кôд еквивалентан комплетној историји Линукс кернела (3,6 милиона Гит објеката) и гура га на један огроман Гит репозиторијум, требало би да прође отприлике 2 године док тај репозиторијум буде садржао довољно објеката да има 50% вероватноће за једну једину SHA-1 колизију објеката. Дакле, природна SHA-1 колизија је мање вероватна од тога да у истој ноћи, у невезаним инцидентима сваког од чланова вашег програмерског тима нападну и убију вукови.

Ако томе посветите рачунарску снагу вредну неколико хиљада долара, могуће је да се синтетишу два фајла са истом контролном сумом, као што је у фебруару 2017. године доказано на https://shattered.io/. Програм Гит прелази на SHA256 као подразумевани алгоритам хеширања, јер је он много отпорнији на нападе колизијом, и садржи уграђен кôд којим се овај напад ублажава (мада није могуће да се потпуно елиминише).

Референце грана

Један једноставан начин да се наведе одређени комит може да се употреби ако је то комит на врху неке гране; тада у било којој Гит команди која очекује референцу на комит просто можете да наведете име гране. Не пример, ако желите да испитате последњи комит објекат на грани, следеће две команде су еквивалентне, под претпоставком да грана topic1 показује на ca82a6d:

$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1

Ако желите да видите на који тачно SHA-1 грана показује, или ако желите да видите на шта се своди било који од ових примера у смислу SHA-1 вредности, можете употребити Гит водоводни алат под називом rev-parse. За више информација у вези водоводних алата, можете погледати Гит изнутра; у основи, rev-parse служи за операције ниског нивоа и није дизајнирана за свакодневне операције. Међутим, понекада може бити од помоћи када желите да видите шта се заиста догађа. Овде над својом граном можете да извршите rev-parse.

$ git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949

RefLog кратка имена

Једна од ствари које програм Гит обавља у позадини док ви радите је да чува reflog – лог у којем чува где су се у последњих неколико месеци налазили ваш HEAD и референце грана.

Свој reflog можете погледати командом 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

Сваки пут када се из неког разлога ажурира врх ваше гране, програм Гит ту информацију чува у овој привременој историји. Reflog податке такође можете искористите и да наведете старије комитове. На пример, ако желите да видите пету претходну вредност показивача HEAD вашег репозиторијума, можете да искористите @{5} референцу коју видите у reflog излазу:

$ git show HEAD@{5}

Ову синтаксу можете и да употребите ако желите да видите где је пре неког одређеног времена била грана. Рецимо, да видите где је јуче била ваша master грана, откуцајте:

$ git show master@{yesterday}

То би вам приказало где је јуче био врх master гране. Ова техника функционише само за податке који се још увек налазе у вашем reflog дневнику, тако да је не можете употребити за комитове старије од неколико месеци.

Ако желите да се reflog информације форматирају као git log излаз, можете да извршите 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'

Важно је приметити да су reflog информације стриктно локалне – то је дневник онога што сте ви урадили у свом репозиторијуму. Референце неће бити исте у нечијој копији репозиторијума; а такође и непосредно након што иницијално клонирате репозиторијум, reflog ће бити празан јер се још увек није догодила никаква активност у репозиторијуму. Извршавање git show HEAD@{2.months.ago} ће вам приказати одговарајући комит само ако сте клонирали пројекат барем пре два месеца – ако сте га клонирали раније од тога, видећете само свој први локални комит.

Савет
Посматрајте reflog као Гитову верзију историје љуске

Ако познајете ЈУНИКС или Линукс, reflog можете сматрати за Гитову верзију историје љуске, што јасно наглашава чињеницу да је оно што се тамо налази важно само за вас и за вашу „сесију” и не тиче се миког другог ко можда ради на истој машини.

Белешка
Означавање заграда у PowerShell

Када се користи PowerShell, заграде као што су { и } представљају специјалне карактере и морају да се означе. Можете их означити краткоузлазним акцентом ` или да их у комит референцама поставите унутар знакова навода:

$ git show HEAD@{0}     # НЕЋЕ радити
$ git show HEAD@`{0`}   # ОК
$ git show "HEAD@{0}"   # ОК

Референце на предаке

Још један главни начин за навођење комитова је путем његових предака. Ако на крај референце поставите ^, програм Гит то разрешава у значење родитеља наведеног комита. Рецимо да погледате у историју свог пројекта:

$ 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

Претходни комит можете видети тако што наведете HEAD^, што значи „родитељ од 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'
Белешка
Означавање циркумфлекса на Виндоуз систему

У cmd.exe на Виндоуз систему, ^ је специјални карактер и мора да се третира другачије. Можете или да га удвојите, или да референцу на комит ставите унутар знакова навода:

$ git show HEAD^     # НЕЋЕ радити на Виндоуз систему
$ git show HEAD^^    # OK
$ git show "HEAD^"   # OK

Такође можете да наведете и број након ^ – на пример, d921970^2 значи „други родитељ од d921970”. Ова синтакса је корисна само код комитова спајања који имају више од једног родитеља. Први родитељ је грана на којој сте били када сте покренули спајање, а други је комит на грани у коју се спајате:

$ 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

Још једна главна спецификација родитељства је ~. Ово такође показује на првог родитеља, тако да су HEAD~ и HEAD^ исто. Разлика се јавља када наведете број. HEAD~2 значи „први родитељ првог родитеља”, или „деда” – она пролази по првим родитељима онолико пута колико наведете. На пример, у историји наведеној раније, 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

Ово такође може да се наведе и као HEAD~~~, што представља првог родитеља од првог родитеља од првог родитеља:

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

    Ignore *.gem

Ове синтаксе такође можете и да комбинујуете – са HEAD~3^2 можете добити другог родитеља претходне референце (под претпоставком да је то комит спајања) и тако даље.

Опсези комитова

Сада када можете да наведете појединачне комитове, хајде да видимо како се наводе опсези комитова. То је од посебне користи за управљање гранама – ако имате доста грана, можете употребити навођења опсега за одговоре на питања као што је „који рад на овој грани још увек спојен у моју главну грану?”

Двострука тачка

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

Пример историје за избор опсега
Слика 136. Пример историје за избор опсега

Желите да видите шта из ваше експерименталне гране још увек није спојено у вашу master грану. Можете затражити да вам програм Гит прикаже лог само тих комитова помоћу master..experiment – што значи „сви комитови до којих може да се дође из experiment али до којих не може да се дође од master”. У циљу јасноће и сажетости, у следећим примерима ће се уместо стварног лог излаза користити слова комит објеката са дијаграма у редоследу у којем би се приказали:

$ git log master..experiment
D
C

С друге стране, ако бисте желели да видите супротно – све комитове у master који нису у experiment – можете да замените места гранама. experiment..master вам приказује све у master до чега не може да се стигне из experiment:

$ git log experiment..master
F
E

Ово је корисно ако желите да experiment грану одржавате ажурном и да најпре погледате шта ћете то спојити. Још једна честа употреба ове синтаксе је се види шта ће те управо гурнути на удаљени репозиторијум:

$ git log origin/master..HEAD

Ова команда вам приказује све комитове у вашој текућој грани који се не налазе у master грани origin удаљеног репозиторијума. Ако извршите git push и ваша текућа грана прати origin/master, комитови које прикаже git log origin/master..HEAD су комитови који ће се пренети на сервер. Једну страну синтаксе можете да изоставите, па програм Гит онда узима да то значи HEAD. На пример, исти резултат као у претходном примеру можете добити ако откуцате git log origin/master.. – програм Гит замењује оно што недостаје на једној страни са HEAD.

Вишеструке тачке

Синтакса двоструке тачке је корисна као скраћеница, али вероватно бисте желели да наведете више од две гране када желите да задате ревизију, као што је приказ комитова који се налазе у било којој од неколико грана и који се не налазе у грани на којо се тренутно налазите. Програм Гит вам омогућава да то урадите било карактером ^ било са --not испред оне референце за коју не желите да видите комитове коју су доступни из ње. Тако да су следеће три команде еквивалентне:

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

То је корисно, јер овом синтаксом у свом упиту можете да наведете више од две референце, што није могуће употребом синтаксе са двоструком тачком. На пример, ако желите да видите све комитове до којих може да се дође из refA или refB, али не може из refC, можете да откуцате било коју од следеће две команде:

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

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

Трострука тачка

Последња главна синтакса избора опсега је синтакса троструке тачке која наводи све комитове до којих може да се дође из било које од датих референци, али не из обе истовремено. Погледајте претходни пример историје комитова у Пример историје за избор опсега. Ако желите да видите шта се налази у master или experiment али не и заједничке референце, можете да извршите:

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

Да поновимо, ово вам исписује обичан log излаз, али приказује само комит информације за ова четири комита, које се појављују у традиционалном редоследу по датуму комитовања.

У овом случају је уопбичајено да се у команди log користи прекидач --left-right који вам приказује на којој страни опсега се налази сваки од комитова. Тако су подаци још кориснији:

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

Помоћу ових алата можете много лакше навести програму Гит комит или комитове које желите да испитате.