-
1. Početak
- 1.1 O kontroli verzije
- 1.2 Kratka istorija Gita
- 1.3 Osnove Gita
- 1.4 Komandna linija
- 1.5 Instaliranje Gita
- 1.6 Podešavanja za prvi put
- 1.7 Traženje pomoći
- 1.8 Rezime
-
2. Osnove Gita
- 2.1 Pravljenje Git repozitorijuma
- 2.2 Snimanje promena na repozitorijumu
- 2.3 Pregled istorije komitova
- 2.4 Opovrgavanje
- 2.5 Rad sa udaljenim repozitorijumima
- 2.6 Tagovanje
- 2.7 Alijasi
- 2.8 Rezime
-
3. Grananje u Gitu
- 3.1 Grananje ukratko
- 3.2 Osnove grananja i spajanja
- 3.3 Upravljanje granama
- 3.4 Tokovi rada sa grananjem
- 3.5 Udaljene grane
- 3.6 Rebaziranje
- 3.7 Rezime
-
4. Git on the Server
- 4.1 Protokoli
- 4.2 Postavljanje Gita na server
- 4.3 Generisanje javnog SSH ključa
- 4.4 Podešavanje servera
- 4.5 Git Daemon
- 4.6 Pametan HTTP
- 4.7 GitWeb
- 4.8 Opcije za hostovanje koje nude treća lica
- 4.9 Rezime
-
5. Distribuirani Git
- 5.1 Distribuirani tokovi rada
- 5.2 Kako doprineti projektu
- 5.3 Održavanje projekta
- 5.4 Rezime
-
6. GitHub
-
7. Git Tools
- 7.1 Revision Selection
- 7.2 Interactive Staging
- 7.3 Stashing and Cleaning
- 7.4 Signing Your Work
- 7.5 Searching
- 7.6 Rewriting History
- 7.7 Reset Demystified
- 7.8 Advanced Merging
- 7.9 Rerere
- 7.10 Debugging with Git
- 7.11 Submodules
- 7.12 Bundling
- 7.13 Replace
- 7.14 Credential Storage
- 7.15 Summary
-
8. Prilagođavanje Gita
- 8.1 Konfiguracija Gita
- 8.2 Git atributi
- 8.3 Git hukovi
- 8.4 Primer polise sprovedene od strane Gita
- 8.5 Rezime
-
9. Git i ostali sistemi
- 9.1 Git kao klijent
- 9.2 Migriranje na Git
- 9.3 Rezime
-
10. Git iznutra
- 10.1 Vodovod i porcelan
- 10.2 Git objekti
- 10.3 Git reference
- 10.4 Paketoteke
- 10.5 Refspek
- 10.6 Transfer Protocols
- 10.7 Maintenance and Data Recovery
- 10.8 Environment Variables
- 10.9 Summary
-
A1. Appendix A: Git in Other Environments
- A1.1 Graphical Interfaces
- A1.2 Git in Visual Studio
- A1.3 Git in Eclipse
- A1.4 Git in Bash
- A1.5 Git in Zsh
- A1.6 Git in Powershell
- A1.7 Summary
-
A2. Appendix B: Embedding Git in your Applications
- A2.1 Command-line Git
- A2.2 Libgit2
- A2.3 JGit
-
A3. Appendix C: Git Commands
- A3.1 Setup and Config
- A3.2 Getting and Creating Projects
- A3.3 Basic Snapshotting
- A3.4 Branching and Merging
- A3.5 Sharing and Updating Projects
- A3.6 Inspection and Comparison
- A3.7 Debugging
- A3.8 Patching
- A3.9 Email
- A3.10 External Systems
- A3.11 Administration
- A3.12 Plumbing Commands
3.6 Grananje u Gitu - Rebaziranje
Rebaziranje
U Gitu, postoje dva glavna načina za integraciju promena iz jedne grane u drugu: merge
i rebase
.
U ovom odeljku ćete naučiti šta je rebaziranje, kako se radi, zašto je to prilično dobra stvarčica, i kada treba a kada ne treba da je koristite.
Osnovno rebaziranje
Ako se vratite na raniji primer iz Osnove spajanja, videćete da ste divergirali svoj rad i napravili komitove na različitim granama.

Najlakši način da integrišete grane, što smo već pokrili, jeste pomoću komande merge
.
Ona će uraditi trostruki spoj između dva poslednja snimka sa grana (C3
i C4
) i njihovog najskorašnjijeg zajedničkog pretka (C2
), stvarajući novi snimak (i komit).

Međutim, postoji još jedan način: možete da uzmete zakrpu promene koja je predstavljena u C4
i da je ponovo primenite preko C3
.
U Gitu se ovo zove rebaziranje.
Pomoću rebase
komande, možete da uzmete sve promene koje su komitovane na jednu granu i da ih ponovite na drugoj.
U ovom primeru, pokrenuli biste sledeće:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
Radi tako što ode na zajedničkog pretka dveju grana (onih na kojoj ste sad i one sa kojom rebazirate), uzima razliku koja je stvorena komitovima na grani na kojoj se nalazite, pamti te razlike u fajlovima koje čuva samo trenutno, resetuje trenutnu granu prema istom komitu na kome je grana ka kojoj rebazirate, i konačno primenjuje svaku promenu.

C4
i C3
.U ovom trenutku, možete da se vratite nazad na master
granu i da uradite spoj tehnikom motanja unapred.
$ git checkout master
$ git merge experiment

master
grane unapred.Sada, snimak na koji pokazuje C4'
je potpuno isti kao i onaj na koji je pokazivao C5
u primeru spoja.
Nema razlike u krajnjem proizvodu integracije, ali rebaziranjem se postiže čistija istorija.
Ako istražite log rebazirane grane, izgleda kao linearna istorija: izgleda kao da se sav rad odvijao serijski, iako su se stvari zapravo odvijale paralelno.
Ovo ćete često raditi da biste se postarali da se komitovi primene na udaljenu granu kako valja — možda u projektu kojem želite da kontribuirate ali ne želite da ga održavate.
U ovom slučaju, radili biste svoj posao na jednoj grani i onda biste rebazirali svoj rad u origin/master
kada ste spremni da pošaljete svoje zakrpe glavnom projektu.
Na ovaj način, održavalac ne mora da radi nikakvu integraciju — samo treba da premota unapred.
Obratite pažnju na to da je snimak na koji pokazuje konačni komit, bilo da je to poslednji od rebaziranih komitova za rebaziranje ili konačni spojni komit nakon spoja, jedan te isti — samo se istorija razlikuje. Rebaziranje ponavlja promene iz jedne linije rada u drugu i to redom kojim su pravljene, dok spajanje uzima krajnje tačke i meša ih u jedno.
Interesantniji slučajevi rebaziranja
Možete da rebazirate nad nečime što nije odredišna grana za rebaziranje.
Uzmite istoriju kao Istorija sa tematskom granom izvedenom iz druge tematske grane., na primer.
Odgranali ste se tematskom granom (server
) da biste dodali neku funkcionalost u vezi sa serverom u projekat, i napravili komit.
Onda se odgranali od toga da biste napravili neke promene sa strane klijenta (client
) i komitovali nekoliko puta.
Konačno, vratili ste se na server
granu i napravili još nekoliko komitova.

Pretpostavimo da ste odlučili da želite da spojite promene na grani client
sa glavnom granom, ali želite da odložite promene na server
grani dok ih bolje ne testirate.
Možete da uzmete promene sa client
grane koje nisu na serveru (C8
i C9
) i da ih ponovite na master
grani koristeći opciju --onto
komande git rebase
:
$ git rebase --onto master server client
Ovo u suštini kaže, "Proveri granu client
, shvati koje zakrpe postoje u odnosu na zajedničkog pretka grana client
i server
, i onda ih ponovo primeni na master
".
Malo je složeno, ali rezultat je odličan.

Sada možete da premotate unapred granu master
(vidite Motanje master
grane unapred da biste obuhvatili promene sa grane client
.):
$ git checkout master
$ git merge client

master
grane unapred da biste obuhvatili promene sa grane client
.Recimo da ste odlučili da povučete i server
granu.
Možete da rebazirate server
granu u master
granu a da ne morate da je prvo čekautujete sa git rebase [osnovna-grana] [tematska-grana]
— što čekautuje tematsku granu (u ovom slučaju server
) i primenjuje pronađene promene na osnovnu granu (master
).
$ git rebase master server
Ovo ponavlja promene nađene na grani server
na grani master
, kao što se vidi na Rebaziranje server
grane na master
grani..

server
grane na master
grani.Onda premotate unapred osnovnu granu (master
):
$ git checkout master
$ git merge server
Možete da obrišete grane client
i server
jer je sav rad obavljen na njima sada integrisan i više vam neće biti potreban, a istorija celokupnog rada će izgledati kao na Konačna istorija komitova:
$ git branch -d client
$ git branch -d server

Opasnosti prilikom rebaziranja
Ah, ali blaženstvo rebaziranja nije bez mana, što se može sumirati samo jednom rečenicom:
Ne rebazirajte komitove koji postoje van vašeg repozitorijuma.
Ako se držite te smernice, sve će biti u redu. Ako ne, ljudi će vas mrzeti, a porodica i prijatelji će vas prezirati.
Kada rebazirate stvari, napuštate postojeće komitove i stvarate nove koji su slični ali drugačiji.
Ako gurnete komitove negde i ostali povuku s njih i baziraju svoj rad nad njima, a onda pišete preko tih komitova sa git rebase
i gurnete ih ponovo, vaši kolaboratori će morati da ponovo spoje sav svoj rad i onda će nastati haos kada probate da povučete njihov rad nazad ka sebi.
Pogledajmo primer koji pokazuje kako rebaziranje koje ste napravili javnim može da izazove probleme. Pretpostavimo da ste napravili klon sa centralnog servera i onda radili nešto nad time. Istorija komitova izgleda ovako:

Sada, neko drugi uradi još nekoliko stvari i uključi to u spoj, a zatim gurne sve na centralni server. Vi to preuzmete i spojite novu udaljenu granu na ono što ste uradili, pa istorija izgleda nekako ovako:

Osoba koja je gurnula spojen rad zatim odluči da se vrati nazad i rebazira ono što je odradila; on ili ona uradi git push --force
da bi se pisalo preko istorije na serveru.
Vi onda preuzmete sa tog servera, dovlačeći nove komitove.

Sada ste oboje u neprilici.
Ako uradite git pull
, napravićete spojni komit koji uključuje obe linije istorije, i repozitorijum će izgledati ovako:

Ako pokrenete git log
dok vam istorija izgleda ovako, videćete dva komita koji imaju istog autora, vreme i poruku, što zna da zbunjuje.
Štaviše, ako gurnete ovu istoriju nazad na server, ponovo ćete uvesti sve te rebazirane komitove na centralni server, što će dalje zbunivati ljude.
Pretpostavlja se da drugi programer ne želi da se C4
i C6
nađu u istoriji; zato su uopšte i radi rebaziranje.
Rebaziranje za rebaziranje
Ako se ipak nađete u ovakvoj situaciji, Git ima još neke čarolije koje vam mogu pomoći. Ako neko iz tima nasilno gurne promene koje preklope ono nad čime ste vi bazirali svoj rad, izazov koji vam se nameće je da provalite šta je vaše a šta je on dodao.
Ispostavlja se da pored SHA-1 čeksume vezane za komit, Git računa i čeksumu koja je bazirana samo na zakrpi koja je uvedena sa komitom. Ovo se zove "identifikacioni broj zakrpe".
Ako povučete rad koji je prepisan i rebazirate navrh toga sa novim komitovima vašeg partnera, Git često ume sam da provali šta je jedinstveno vaše i da primeni to nazad na vrh nove grane.
Na primer, u prethodnom scenariju, ako umesto spoja kada smo bili kod Neko gurne rebazirane komitove, napuštajući komitove nad kojima ste bazirali vaš rad. pokrenemo git rebase teamone/master
, Git će:
-
odrediti koji rad je jedinstven za našu granu (
C2
,C3
,C4
,C6
iC7
), -
odrediti šta nisu spojni komitovi (
C2
,C3
iC4
), -
odrediti šta nije prepisano u odredišnu granu (samo
C2
iC3
, pošto jeC4
ista zakrpa kao iC4'
) i -
primeniti te komitove na
teamone/master
granu.
Zato ćemo, umesto rezultata koji vidimo na Ponovno spajanje istog rada u novi spojni komit., dobiti nešto što više podseća na Rebaziranje na nasilno gurnuto rebaziranje..

Ovo će da upali samo ako C4
i C4'
koje je vaš partner napravio čine skoro identičnu zakrpu.
U suprotnom, rebaziranjem neće moći da se ustanovi da je to duplikat i biće dodata još jedna zakrpa koja podseća na C4
(koja verovatno neće uspeti da se čisto primeni, jer će promene već bar delimično biti tamo).
Ovo možete da uprostite i pokretanjem git pull --rebase
umesto običnog git pull
.
Ili možete da uradite to ručno sa git fetch
za kojim sledi git rebase teamone/master
u ovom slučaju.
Ako koristite git pull
i želite da --rebase
bude podrazumevana opcija, možete da podesite pull.rebase
vrednost iz konfiguracionog fajla na true
sa git config --global pull.rebase true
.
Ako rebaziranje posmatrate kao način da pospremite i radite sa komitovima pre nego što ih gurnete, i ako samo rebazirate komitove koji nikad nisu bili dostupni javno, sve će biti u redu. Ako rebazirate komitove koji su već gurnuti javno, i ljudi baziraju svoj rad nad tim komitovima, onda ćete se naći u frustrirajućim situacijama i bićete meta prezira svojih saradnika.
Ako vi ili partner u nekom trenutku shvatite da je ovakav sled događaja neophodan, postarajte se da svi znaju da treba da pokrenu git pull --rebase
da probaju da učine stvar barem malo jednostavnijom.
Rebaziranje protiv spajanja
Sada kada ste videli kako deluje rebaziranje a kako spajanje, možda se pitate šta je bolje. Pre nego što damo odgovor na ovo, hajde da načinimo korak unazad i popričamo malo o tome šta je zapravo istorija.
Jedna tačka gledišta na ovo je to da je istorija komitova vašeg repozitoijuma zapis onoga što se zapravo dogodilo. To je istorijski dokument, vredan na svoj način, i ne bi trebalo da se čačka. Iz ovog ugla, menjanje istorije komita je skoro pa bogohuljenje; vi lažete o onome što se zapravo dogodilo. Šta onda raditi kada se dogodi serija zbrkanih komitova? Tako su se stvari dogodile, i repozitorijum treba da sačuva to za potomstvo.
Suprotna tačka gledišta je da je istorija komitova priča o tome kako je projekat napravljen. Ne biste objavili prvu skicu knjige, a upustvo za održavanje softvera zaslužuje brižljivo redigovanje. Ovaj tabor koristi alate kao što je rebaziranje i filter grane da bi ispričao priču onako kako je najbolje da je pročita budući čitalac.
Sada, što se tiče pitanja da li je spajanje ili rebaziranje bolje: nadamo se da ćete videti da stvari nisu tako jednostavne. Git je moćan alat, dopušta vam da uradite mnoge stvari sa istorijom, ali svaki tim i svaki projekat je drugačiji. Sada kada znate kako obe ove stvari rade, na vama je da odlučite šta je bolje za vašu konkretnu situaciju.
U opštem slučaju, najbolji način da iskoristite prednost oba sveta je da rebazirate lokalne promene koje ste napravili ali još niste podelili pre nego što ih gurnete kako biste očistili istoriju, ali da nikad ne rebazirate ništa što ste negde gurnuli.