Git
Chapters ▾ 2nd Edition

3.1 Grananje u Gitu - Grananje ukratko

Skoro svaki VCS ima neku vrstu podrške za grananje. Grananje znači da se divergira od glavne linije razvitka programa i da se nastavi rad bez uticaja na tu glavnu liniju. U mnogim VCS alatima, ovo je nešto skuplji proces, jer se često zahteva pravljenje nove kopije direktorijuma sa izvornim kodom, što zna da potraje za veće projekte.

Neki ljudi Gitov model grananja zovu prvoklasnom osobinom, i zaista, mogućnost koje nudi odvaja Git od ostalih VCS-ova. Ali po čemu je poseban? Način na koji se Git grana je neverovatno jednostavan za obradu, što čini da se operacije grananja izvrše skoro u istom trenutku kada se zadaju, a skakanje s jedne na drugu granu je podjednako brzo. Za razliku od mnogih drugih VCS-ova, Git ohrabruje korišćenje tokova rada koji se često granaju i spajaju, čak i nekoliko puta tokom jednog dana. Razumevanje i savladavanje ove tehnike predstavljaće snažno i unikatno oruđe koje bi u potpunosti moglo da promeni način na koji razvijate svoj proizvod.

Grananje ukratko

Da bismo stvarno razumeli kako Git barata grananjem, moramo da se odmaknemo korak unazad i da istražimo kako Git čuva podatke.

Kao što se možda sećate iz Početak, Git ne čuva podatke kao seriju skupa promena ili razlika, već kao seriju snimaka.

Kada napravite komit, Git čuva komit-objekat koji sadrži pokazivač na snimak objekta koji je stejdžovan. Ovaj objekat sadrži i autorovo ime i mejl, poruku koja je ukucana, i pokazivače na komit ili komitove koji su direktno došli pre ovog komita (roditelja ili roditelje): nula roditelja na inicijalni komit, jednog roditelja za normalni komit, i više roditelja za komit koji je rezultat spajanja dveju ili više grana.

Da bismo vizualizovali ovo, pretpostavimo da imate direktorijum koji sadrži tri fajla, i sve ih stejdžujete a zatim komitujete. Stejdžovanje fajlova računa kontrolnu sumu nad svakim od njih (SHA-1 heš kako smo pomenuli u Početak), čuva tu verziju fajla u Git repozitorijumu (Git to naziva blobovima) i dodaje tu kontrolnu sumu na stejdž:

$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'

Kada napravite komit sa git commit, Git pravi kontrolnu sumu svakog poddirektorijuma (u ovom slučaju, samo koreni direktorijum projekta) i čuva ta stabla u Git repozitorijumu. Git onda kreira komit-objekat koji ima metapodatke i pokazivač na koren stabla projekta tako da može da ponovo kreira taj snimak kada nam bude bio potreban.

Vaš Git repozitorijum sada sadrži pet objekata: jedan blob za sadržaj svakog og tri fajla, jedno stablo koje sadrži listu sadržaja direktorijuma i specificira koja imena fajlova su sačuvana u kom blobu, i jedan komit sa pokazivačem na taj koren stabla i sve komit metapodatke.

Komit i njegovo stablo.
Figure 9. Komit i njegovo stablo

Ako napravite neke izmene i komitujete ponovo, sledeći komit čuva pokazivač na komit koji je došao odmah pre njega.

Komitovi i njihovi roditelji.
Figure 10. Komitovi i njihovi roditelji

Grana u Gitu je jednostavno mali pokretni pokazivač na jedan od ovih komitova. Podrazumevano ime grane u Gitu je master. Kada počnete da komitujete, daje vam se master grana koja pokazuje na poslednji komit koji ste napravili. Svaki put kada komitujete, kreće se napred automatski.

Note

master grana u Gitu nije posebna grana. Ona je ista kao i svaka druga grana. Jedini razlog zbog kojeg skoro svaki repozitorijum ima takvu granu je to što je komanda git init napravi po podrazumevanim podešavanjima i većina ljudi nema potrebu da je menja.

Grana i njena istorija komitova.
Figure 11. Grana i njena istorija komitova

Pravljenje nove grane

Šta se dešava kada napravite novu granu? Pa, kada to uradite, stvara vam se novi pokazivač kojim se krećete unaokolo. Recimo da napravite novu granu koju ćete nazvati testing. Ovo se radi komandom git branch:

$ git branch testing

Ovo stvara novi pokazivač na isti komit na kom se trenutno nalazite.

Dve grane pokazuju na istu seriju komitova.
Figure 12. Dve grane pokazuju na istu seriju komitova

Kako Git zna na kojoj se grani trenutno nalazite? Čuva poseban pokazivač koji se zove HEAD. Obratite pažnju na to da je ovo mnogo drugačije od koncepta HEAD-a u drugim VCS-ovima na koje ste možda navikli, kao što su Subversion ili CVS. U Gitu, ovo je pokazivač na lokalnu granu na kojoj se trenutno nalazite. U ovom slučaju, još uvek ste na master grani. Komandom git branch ste samo napravili novu granu — niste prešli na nju.

`HEAD` pokazuje na granu.
Figure 13. HEAD pokazuje na granu.

Ovo lako možete da vidite tako što ćete pokrenuti običnu komandu git log koja vam pokazuje gde pokazuju pokazivači na grane. Ova opcija se zove --decorate.

$ git log --oneline --decorate
f30ab (HEAD -> master, testing) add feature #32 - ability to add new formats to the central interface
34ac2 Fixed bug #1328 - stack overflow under certain conditions
98ca9 The initial commit of my project

Vidite da su master i testing grane odmah pored komita f30ab.

Menjanje grana

Da biste se prebacili na postojeću granu, treba da pokrenete komandu git checkout. Hajde da se prebacimo na novu granu testing:

$ git checkout testing

Ovo pomera pokazivač HEAD na granu testing.

`HEAD` pokazuje na trenutnu granu.
Figure 14. HEAD pokazuje na trenutnu granu.

Čemu ovo? Pa, hajde da uradimo još jedan komit:

$ vim test.rb
$ git commit -a -m 'made a change'
`HEAD` grana se pomera napred kada se napravi komit.
Figure 15. HEAD grana se pomera napred kada se napravi komit.

Ovo je zanimljivo, jer se sada grana testing pomerila napred, ali grana master još uvek pokazuje na komit na kome ste bili kada ste pokrenuli git checkout da promenite grane. Hajde da se vratimo nazad na granu master:

$ git checkout master
`HEAD` se pomera kada uradite čekaut.
Figure 16. HEAD se pomera kada uradite čekaut.

Ova komanda je uradila dve stvari. Pomerila je pokazivač HEAD nazad na mesto u grani master, i vratila je fajlove u radnom direktorijumu na snimak na koji pokazuje master. Ovo takođe znači da će promene koje pravite odsad pa nadalje divergirati od stare verzije projekta. Bukvalno se vraćate nazad poništavajući ono što ste uradili u testing grani da biste mogli da krenete drugim putem.

Note
Menjanje grana menja fajlove u radnom direktorijumu

Važno je primetiti da će se fajlovi u radnom direktorijumu promeniti kada skačete s grane na granu. Ako se prebacite na stariju granu, radni direktorijum će se vratiti na izgled koji je imao u vreme kada ste komitovali na toj grani. Ako Git nije u stanju da to uradi bez problema, neće vam dati da se prebacite uopšte.

Hajde da napravimo neke promene i ponovo komitujemo:

$ vim test.rb
$ git commit -a -m 'made other changes'

Sada je istorija vašeg projekta divergirala (pogledate Divergentna istorija). Napravili ste granu, prebacili ste se na nju, uradili nešto na njoj, i onda se vratili nazad na glavnu granu i uradili još malo posla. Obe ove promene su izolovane u posebnim granama: možete da skačete s jedne na drugu napred-nazad i da ih spojite kada budete bili spremni. I sve ste to uradili prostim komandama branch, checkout i commit.

Divergentna istorija.
Figure 17. Divergentna istorija

Ovo lako možete pogledati i sa git log komandom. Ako pokrenete git log --oneline --decorate --graph --all, odštampaće vam se istorija komitova, pokazujući vam gde se sada nalaze pokazivači na grane i kako je istorija divergirala.

$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) made other changes
| * 87ab2 (testing) made a change
|/
* f30ab add feature #32 - ability to add new formats to the
* 34ac2 fixed bug #1328 - stack overflow under certain conditions
* 98ca9 initial commit of my project

Pošto je grana u Gitu zapravo jednostavan fajl koji sadrži 40 karaktera SHA-1 čeksume na koju pokazuje komit, pravljenje i uništavanje grana je jeftino. Napraviti novu granu je brzo i jednostavno koliko i upisivanje 41 bajta u fajl (40 slova i nova linija).

Ovo je u oštrom kontrastu sa načinom na koji radi većina starijih alata za grananje u VCS-ovima, u kojima je potrebno kopirati sve fajlove projekta u drugi direktorijum. Ovo može potrajati nekoliko sekundi ili čak minuta, u zavisnosti od veličine projekta, dok je u Gitu ovakav proces uvek trenutan. Takođe, pošto beležimo roditelje kada komitujemo, pronalaženje odgovarajuće baze za spajanje se automatski odradi umesto da se mi bavimo time i u opštem slučaju je taj proces veoma jednostavan. Ove osobine podstiču programere da često prave i koriste grane.

Hajde da pogledamo zašto to treba da radite.