-
1. Začetek
- 1.1 O nadzoru različic
- 1.2 Kratka zgodovina Gita
- 1.3 Kaj je Git?
- 1.4 Ukazna vrstica
- 1.5 Namestitev Gita
- 1.6 Prva nastavitev Gita
- 1.7 Pridobivanje pomoči
- 1.8 Povzetek
-
2. Osnove Git
- 2.1 Pridobivanje repozitorija Git
- 2.2 Snemanje sprememb v repozitorij
- 2.3 Pregled zgodovine potrditev
- 2.4 Razveljavljanje stvari
- 2.5 Delo z daljavami
- 2.6 Označevanje
- 2.7 Aliasi Git
- 2.8 Povzetek
-
3. Veje Git
- 3.1 Veje na kratko
- 3.2 Osnove vej in združevanja
- 3.3 Upravljanje vej
- 3.4 Poteki dela z vejami
- 3.5 Oddaljene veje
- 3.6 Ponovno baziranje
- 3.7 Povzetek
-
4. Git na strežniku
- 4.1 Protokoli
- 4.2 Pridobitev Gita na strežniku
- 4.3 Generiranje vaših javnih ključev SSH
- 4.4 Nastavitev strežnika
- 4.5 Prikriti proces Git
- 4.6 Pametni HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Možnosti gostovanja pri tretjih ponudnikih
- 4.10 Povzetek
-
5. Porazdeljeni Git
- 5.1 Porazdeljeni poteki dela
- 5.2 Prispevek k projektu
- 5.3 Vzdrževanje projekta
- 5.4 Povzetek
-
6. GitHub
-
7. Orodja Git
- 7.1 Izbira revizije
- 7.2 Interaktivno pripravljanje
- 7.3 Shranjevanje na varno (angl. stashing) in čiščenje
- 7.4 Podpisovanje vašega dela
- 7.5 Iskanje
- 7.6 Prepisovanje zgodovine
- 7.7 Demistifikacija ponastavitve
- 7.8 Napredno združevanje
- 7.9 Rerere
- 7.10 Razhroščevanje z Gitom
- 7.11 Podmoduli
- 7.12 Povezovanje v pakete
- 7.13 Zamenjava
- 7.14 Shramba poverilnic
- 7.15 Povzetek
-
8. Prilagoditev Gita
- 8.1 Konfiguracija Git
- 8.2 Atributi Git
- 8.3 Kljuke Git
- 8.4 Primer pravilnika, ki ga uveljavlja Git
- 8.5 Povzetek
-
9. Git in ostali sistemi
- 9.1 Git kot odjemalec
- 9.2 Migracija na Git
- 9.3 Povzetek
-
10. Notranjost Gita
- 10.1 Napeljava in keramika
- 10.2 Objekti Git
- 10.3 Reference Git
- 10.4 Packfiles (datoteke zmanjšanih podatkov)
- 10.5 Refspec
- 10.6 Protokoli prenosa
- 10.7 Vzdrževanje in obnovitev podatkov
- 10.8 Spremenljivke okolja
- 10.9 Povzetek
-
A1. Dodatek A: Git v drugih okoljih
- A1.1 Grafični vmesniki
- A1.2 Git v Visual Studio
- A1.3 Git v Visual Studio Code
- A1.4 Git v IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git v Sublime Text
- A1.6 Git v Bashu
- A1.7 Git v Zsh
- A1.8 Git v Powershellu
- A1.9 Povzetek
-
A2. Dodatek B: Vdelava Gita v vašo aplikacijo
- A2.1 Git v ukazni vrstici
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Dodatek C: Ukazi Git
- A3.1 Nastavitev in konfiguracija
- A3.2 Pridobivanje in ustvarjanje projektov
- A3.3 Osnove posnetkov
- A3.4 Veje in združevanje
- A3.5 Deljenje in posodabljanje projektov
- A3.6 Pregled in primerjava
- A3.7 Razhroščevanje
- A3.8 Popravljanje
- A3.9 E-pošta
- A3.10 Zunanji sistemi
- A3.11 Administracija
- A3.12 Orodja za sisteme napeljave
3.6 Veje Git - Ponovno baziranje
Ponovno baziranje
V Gitu obstajata dva glavna načina za integracijo sprememb iz ene veje v drugo: merge
in rebase
.
V tem razdelku se boste naučili, kaj je ponovno baziranje, kako ga narediti, zakaj je precej posebno orodje in v katerih primerih, ga ne boste želeli uporabiti.
Osnovno ponovno baziranje
Če se vrnete na prejšnji primer iz razdelka Osnovno združevanje, lahko vidite, da ste se oddaljili od svojega dela in naredili potrditve na dveh različnih vejah.
![Enostavna različna zgodovina](png/basic-rebase-1.png)
Najenostavnejši način za integracijo vej, kot smo to že pokrili, je ukaz merge
.
Izvede tri-načinsko združevanje med dvema zadnjima posnetkoma vej (C3
in C4
) in najnovejšim zadnjim skupnim prednikom obeh (C2
), kar ustvari nov posnetek (in potrditev).
![Združitev za integracijo zgodovine različnega dela](png/basic-rebase-2.png)
Vendar obstaja še drug način: vzamete programski popravek spremembe, ki je bil uveden v C4
in ga ponovno uporabite na vrhu C3
.
V Gitu se to imenuje ponovno baziranje.
Z ukazom rebase
lahko vzamete vse spremembe, ki so bile potrjene na eni veji, in jih ponovite na drugi veji.
V tem primeru bi izvlekli vejo experiment
in jo nato ponovno bazirali na osnovi veje master
na naslednji način:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
Ta operacije deluje tako, da gre do skupnega prednika obeh vej (tista na kateri ste in druga, katero ponovno bazirate), pridobi razliko uvedeno z vsako potrditvijo veje, na kateri ste, shrani te razlike v začasno datoteko, ponastavi trenutno vejo na isto potrditev, kot je veja, na katero bazirate, in končno v zameno uporabi vsako spremembo.
![Ponovno baziranje spremembe uvedene v `C4` na `C3`](png/basic-rebase-3.png)
C4
na C3
Na tej točki se lahko vrnete na vejo master
in naredite združevanje s hitrim previjanjem naprej (angl. fast-forward merge).
$ git checkout master
$ git merge experiment
![Hitro previjanje naprej veje `master`](png/basic-rebase-4.png)
master
Sedaj je posnetek, na katerega kaže C4
, točno tak kot tisti, ki je bil pokazan na C5
v primeru združitve potrjevanja.
Ni razlike v končnem produktu integracije, vendar ponovno baziranje naredi zgodovino čistejšo.
Če primerjate dnevnik ponovno bazirane veje, je videti kot linearna zgodovina: videti je, kot da se je vse delo zgodilo v serijah, tudi ko se je prvotno zgodilo vzporedno.
Pogostokrat boste to naredili, da zagotovite, da se vaše potrditve uporabijo gladko na oddaljeni veji — mogoče v projektu kateremu poskušate prispevati, vendar ga ne vzdržujete.
V tem primeru bi naredili vaše delo na veji in nato osnovali vaše delo glede na to origin/master
, ko ste pripravljeni poslati svoje popravke glavnemu projektu.
Na ta način vzdrževalcu ni treba narediti nikakršnega integracijskega dela — samo fast-forward ali pa čista uporaba.
Bodite pozorni, saj gre za isti posnetek, na katerega kaže končna potrditev, s katero ste končali, bodisi je ta zadnja od ponovno bazirane potrditve za ponovno baziranje ali pa končna potrditev združevanja po združevanju — samo zgodovina je drugačna. Ponovno baziranje ponovno predvaja spremembe iz ene vrstice dela v drugo v vrstnem redu, kakor so bile uvedene, medtem ko združevanje vzame končne točke in jih združi skupaj.
Bolj zanimivo ponovno baziranje
Svoje ponovno baziranje lahko ponovno predvajate tudi na nečem drugem od ciljne veje ponovnega baziranja.
Za primer vzemimo zgodovino, kot je na sliki Zgodovina s tematsko vejo na osnovi druge tematske veje.
Naredili ste tematsko vejo (server
), da ste svojemu projektu dodali nekaj funkcionalnosti strežniške strani, in naredili ste potrditev.
Nato ste od tam naredili razvejanje (client
), da ste naredili spremembe na strani odjemalca in naredili nekaj potrditev.
Na koncu ste šli nazaj na vašo vejo server
in naredili še nekaj potrditev.
![Zgodovina s tematsko vejo na osnovi druge tematske veje](png/interesting-rebase-1.png)
Predpostavimo, da se odločite, da želite združiti vaše spremembe strani odjemalca v vašo glavno izdajo, vendar želite še malo počakati s spremembami strežniške strani, dokler niso nadaljnje testirane.
Vzamete lahko spremembe na veji client
, ki niso na veji server
(C8
in C9
) in jih ponovno predvajate na vaši veji master
z uporabo možnosti --onto
ukaza git rebase
:
$ git rebase --onto master server client
To v osnovi navede, »Vzemi vejo client
, ugotovi popravke, odkar se je veja ločila od veje server
, in jih nato ponovno predvajaj na veji client
, kakor da je le-ta neposredno osnovana na veji master
«.
Je nekoliko bolj kompleksno, vendar rezultat je precej dober.
![Ponovno baziranje tematske veje na osnovi druge tematske veje](png/interesting-rebase-2.png)
Sedaj lahko naredite hitro previjanje naprej (angl. fast-forward) na vaši veji master
(glejte sliko Hitro previjanje naprej vaše veje master
, da vključuje spremembe veje client
):
$ git checkout master
$ git merge client
![Hitro previjanje naprej vaše veje `master`, da vključuje spremembe veje `client`](png/interesting-rebase-3.png)
master
, da vključuje spremembe veje client
Recimo, da se odločite povleči to tudi v vašo vejo server
.
Ponovno baziranje lahko naredite na veji server
glede na vejo master
, brez da jo morate najprej izvleči s pogonom git rebase <basebranch> <topicbranch>
— kar vam izvleče tematsko vejo (v tem primeru server
) in jo ponovno predvaja na osnovni veji (master
):
$ git rebase master server
To ponovno predvaja vaše delo server
na vrhu vašega dela master
, kot je prikazano na sliki Ponovno baziranje vaše veje server
na vrhu vaše veje master
.
![Ponovno baziranje vaše veje `server` na vrhu vaše veje `master`](png/interesting-rebase-4.png)
server
na vrhu vaše veje master
Nato lahko naredite fast-forward na osnovni veji (master
):
$ git checkout master
$ git merge server
Veji client
in server
lahko odstranite, ker je celotno delo integrirano in ju ne potrebujete več, kar pusti vašo zgodovino za ta celoten proces, da je videti kot na sliki Končna zgodovina potrditev:
$ git branch -d client
$ git branch -d server
![Končna zgodovina potrditev](png/interesting-rebase-5.png)
Nevarnosti ponovnega baziranja
Ah, vendar blagoslova ponovnega baziranja ni brez njegovih slabih strani, ki jih lahko povzamemo v eni vrstici:
Ne bazirajte ponovno tistih potrditev, ki obstajajo izven vašega repozitorija in na katerih so ljudje morda osnovali delo.
Če sledite tem smernicam, bo v redu. Če ne, vas bodo ljudje sovražili in zaničevani boste s strani prijateljev in družine.
Ko ponovno bazirate, opuščate obstoječe potrditve in ustvarjate nove, ki so podobne vendar drugačne.
Če nekam potisnete potrditve in jih drugi povlečejo ter bazirajo svoje delo na njih, nato pa vi prepišete te potrditve z git rebase
in jih ponovno potisnete, bodo vaši sodelavci morali narediti ponovno združevanje njihovega dela in nastala bo zmešnjava, ko boste poskusili povleči njihovo delo nazaj v vaše.
Poglejmo primer, kako lahko baziranje dela, ki ste ga naredili javno, povzroča probleme. Predpostavimo, da klonirate iz osrednjega strežnika in nato iz tega naredite nekaj dela. Vaša zgodovina potrditev je videti takole:
![Klonirajte repozitorij in bazirajte nekaj dela na njem](png/perils-of-rebasing-1.png)
Sedaj, nekdo drug naredi delo, ki vključuje združitev, in potisne to delo na osrednji strežnik. Prenesete in združite novo oddaljeno vejo v svoje delo, kar naredi, da vaša zgodovina izgleda nekakako takole:
![Prenesite več potrditev in jih združite v svoje delo](png/perils-of-rebasing-2.png)
V nadaljevanju se oseba, ki je potisnila združeno delo, odloči iti nazaj in namesto tega ponovno bazira svoje delo; naredi git push --force
, da prepiše zgodovino na strežniku.
Nato prenesete iz tega strežnika in dobite nove potrditve.
![Nekdo potisne ponovno bazirane potrditve in opusti potrditve, na katerih ste vi osnovali delo](png/perils-of-rebasing-3.png)
Sedaj ste oboji v škripcih.
Če naredite git pull
, boste ustvarili potrditve združitve, ki vključujejo obe vrstici zgodovine, in vaš repozitorij bo videti takole:
![Ponovno združite isto delo v novo potrditev združevanja](png/perils-of-rebasing-4.png)
Če poženete git log
, ko je vaša zgodovina videti takole, boste videli dve potrditvi, ki imata istega avtorja, datum in sporočilo, kar bo zmedeno.
Nadalje, če potisnete to zgodovino nazaj na strežnik, boste ponovno uvedli vse te ponovno bazirane potrditve na osrednjem strežniku, kar lahko dalje zmede ljudi.
Precej prepričano je domnevati, da drug razvijalec ne želi imeti C4
in C6
v zgodovini; to je razlog, zakaj sploh ponovno bazirati.
Ponovno bazirajte, ko ponovno bazirate
Če se najdete v položaju, kot je ta, ima Git nekaj dodatne čarobnosti, ki vam lahko pomaga. Če nekdo v vaši ekipi potisne spremembe, ki prepišejo delo, na katerem ste osnovali svoje delo, je vaš izziv ugotoviti, kaj je vaše in kaj so prepisali drugi.
Izkaže se, da poleg kontrolne vsote SHA-1 potrditve, Git preračuna tudi kontrolno vsoto, ki je osnovana samo kot programski popravek uveden v potrditvi. To se imenuje »patch-id«.
Če povlečete delo, ki je bilo prepisano in osnovano na vrhu nove potrditve vašega partnerja, lahko Git tudi pogostokrat uspešno ugotovi, kaj je unikatno vaše, in to uporabi nazaj na vrhu nove veje.
Na primer, če v prejšnjem scenariju, namesto da delamo združevanje, ko smo na primeru iz slike Nekdo potisne ponovno bazirane potrditve in opusti potrditve, na katerih ste vi osnovali delo, poženemo git rebase teamone/master
, bo Git:
-
Določil, katero delo je unikatno za vašo vejo (
C2
,C3
,C4
,C6
,C7
) -
Določil, katere niso potrditve združevanja (
C2
,C3
,C4
) -
Določil, katere niso bile prepisane v ciljni veji (samo
C2
inC3
, saj jeC4
enak programski popravek kotC4'
) -
Uporabil te potrditve na vrhu
teamone/master
Torej namesto rezultata, ki ga vidimo na sliki Ponovno združite isto delo v novo potrditev združevanja, bi dobili nekaj bolj takega, kot je na sliki Ponovno baziranje na osnovi prisilno potisnjenega ponovno baziranega dela.
![Ponovno baziranje na osnovi prisilno potisnjenega ponovno baziranega dela](png/perils-of-rebasing-5.png)
To deluje zgolj, če sta C4
in C4'
, ki ju je naredil vaš partner skoraj točno enaka popravka.
Drugače ponovno baziranje ne bo zmožno vedeti, da je duplikat in bo dodalo drug C4
podoben programski popravek (ki ga verjetno ne bo uspelo uporabiti na gladek način, saj bi spremembe že bile vsaj nekako tam).
To lahko tudi poenostavite s pogonom git pull --rebase
namesto običajnega git pull
.
Lahko pa to naredite ročno z git fetch
, kateremu v tem primeru sledi git rebase teamone/master
.
Če uporabljate git pull
in želite privzeto narediti --rebase
, lahko nastavite pull.rebase
nastavitveno vrednost z nečim, kot je git config --global pull.rebase true
.
Če ponovno bazirate samo potrditve, ki niso nikoli zapustile vaše naprave, bo v redu. Če ponovno bazirate potrditve, ki so bile potisnjene, vendar ni nihče osnoval dela na njih, bo tudi v redu. Če ponovno bazirate potrditve, ki so bile že javno potisnjene in so na teh potrditvah ljudje lahko osnovali delo, potem ste lahko v frustrirajočih težavah in prezirate člane svoje ekipe.
Če se vam ali partnerju zdi na neki točki to potrebno, zagotovite, da vsi vejo, da morajo pognati git pull --rebase
, tako da poskusijo nekoliko bolj poenostaviti problem, ko se ta zgodi.
Ponovno baziranje v primerjavi z združevanjem
Sedaj, ko ste videli ponovno baziranje in združevanje v delovanju, se lahko sprašujete, kaj je boljše. Preden lahko to odgovorimo, pojdimo korak nazaj in spregovorimo o tem, kaj pomeni zgodovina.
Eno stališče tega je, da je zgodovina potrditev vašega repozitorija posnetek, kaj se je dejansko zgodilo. Je zgodovinski dokument, vreden svojega lastnega prav in ne bi smel biti ponarejen. Iz tega zornega kota je spreminjanje zgodovine potrditev skoraj bogokletno; namreč lažete, kaj se je dejansko zgodilo. Torej, kaj če obstaja grda serija potrditev združevanj? Tako se je zgodilo in repozitorij bi moral to ohraniti zanamcem.
Nasprotno stališče je, da je zgodovina potrditev zgodba, kako je bil vaš projekt narejen.
Prvega osnutka knjige tudi ne bi objavili, torej zakaj bi pokazali svoje nepopolno delo?
Ko delate na projektu, morda potrebujete zapis vseh svojih napačnih korakov in slepih ulic, vendar ko je čas, da pokažete svoje delo svetu, morda želite povedati bolj koherentno zgodbo o tem, kako priti od A do B.
Ljudje v tej skupini uporabljajo orodja, kot sta rebase
in filter-branch
, da prepišejo svoje potrditve, preden se združijo v glavno vejo.
Uporabljajo orodja, kot sta rebase
in filter-branch
, da povedo zgodbo na način, ki je najboljši za prihodnje bralce.
Zdaj, glede vprašanja, ali je boljše združevanje ali ponovno baziranje: upajmo, da boste spoznali, da to ni tako preprosto. Git je zmogljivo orodje in omogoča veliko stvari v zvezi z vašo zgodovino, vendar je vsaka ekipa in vsak projekt drugačen. Ko zdaj veste, kako delujeta oba načina, je odvisno od vas, da se odločite, kateri je najboljši za vaš poseben položaj.
Lahko dobite najboljše iz obeh svetov: pred objavo spremenite lokalne spremembe, da očistite svoje delo, vendar nikoli ne prepišite ničesar, kar ste že objavili drugje.