-
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
7.7 Orodja Git - Demistifikacija ponastavitve
Demistifikacija ponastavitve
Preden se premaknemo na bolj specializirana orodja, se pogovorimo o Gitovih ukazih reset
in checkout
.
Ta ukaza sta ena izmed najbolj zmedenih delov Gita, ko se z njima prvič srečate.
Naredita toliko stvari, da se zdi obupno poskusiti jih dejansko razumeti in pravilno uporabiti.
Za to priporočamo preprosto metaforo.
Tri drevesa
Lažji način razmišljanja o reset
in checkout
je skozi mentalni okvir Gita kot vsebinskega upravitelja treh različnih dreves.
S pojmom »drevo« tukaj dejansko mislimo na »zbirko datotek«, ne nujno na podatkovno strukturo.
Obstajajo nekateri primeri, kjer indeks ne deluje točno kot drevo, vendar je za naše namene za zdaj lažje razmišljati o njem na ta način.
Git v svojem normalnem delovanju kot sistem upravlja in manipulira s tremi drevesi:
Drevo | Vloga |
---|---|
HEAD |
Zadnji posnetek potrditve, naslednja nadrejena |
Indeks |
Predlagan posnetek naslednje potrditve |
Delovni direktorij |
Peskovnik |
HEAD
HEAD je kazalec na trenutno vejno referenco, ki pa je sama po sebi kazalec na zadnjo potrditev, narejeno na tej veji. To pomeni, da bo HEAD nadrejeni naslednje ustvarjene potrditve. Na splošno je najpreprosteje razmišljati o HEAD-u kot o posnetku vaše zadnje potrditve na tej veji.
Dejansko je precej enostavno videti, kako je ta posnetek videti. Tukaj je primer pridobivanja dejanskega seznama direktorijev in kontrolnih vsot SHA-1 za vsako datoteko v posnetku HEAD:
$ git cat-file -p HEAD
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
author Scott Chacon 1301511835 -0700
committer Scott Chacon 1301511835 -0700
initial commit
$ git ls-tree -r HEAD
100644 blob a906cb2a4a904a152... README
100644 blob 8f94139338f9404f2... Rakefile
040000 tree 99f1a6d12cb4b6f19... lib
Gitova ukaza cat-file
in ls-tree
sta ukaza »napeljave«, ki se uporabljata za stvari nižje ravni in nista resnično uporabljena v vsakodnevnem delu, vendar nam pa pomagata videti, kaj se dogaja tukaj.
Indeks
Indeks je vaša naslednja predlagana potrditev.
To zasnovo smo označevali tudi kot Gitovo »področje priprave«, saj si ga Git ogleda, ko zaženete ukaz git commit
.
Git napolni ta indeks s seznamom vsebine datotek, ki so bile nazadnje izvlečene v vaš delovni direktorij, in kako so bile videti, ko so bile prvotno izvlečene.
Nato nekatere od teh datotek nadomestite z novimi različicami in git commit
to pretvori v drevo za novo potrditev.
$ git ls-files -s
100644 a906cb2a4a904a152e80877d4088654daad0c859 0 README
100644 8f94139338f9404f26296befa88755fc2598c289 0 Rakefile
100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb
Tukaj ponovno uporabljamo git ls-files
, ki je bolj ukaz v zakulisju in vam prikaže, kako je trenutno videti vaš indeks.
Indeks tehnično gledano ni drevesna struktura — dejansko je implementiran kot sploščen manifest — vendar za naše namene je dovolj blizu.
Delovni direktorij
Nazadnje imate vaš delovni direktorij (ki se pogosto imenuje tudi »delovno drevo«).
Drugi dve drevesi shranjujeta svojo vsebino na učinkovit, vendar nepraktičen način v direktoriju .git
.
Delovni direktorij jih razpakira v dejanske datoteke, kar vam omogoča lažje urejanje.
Delovni direktorij si lahko predstavljate kot peskovnik, kjer lahko preizkusite spremembe, preden jih potrdite v področje priprave (indeks) in nato v zgodovino.
$ tree
.
├── README
├── Rakefile
└── lib
└── simplegit.rb
1 directory, 3 files
Potek dela
Običajni način dela z Gitom je zabeležiti posnetke vašega projekta v zaporedno boljša stanja z manipulacijo teh treh dreves.
Predstavljajmo si ta proces: recimo, da vstopite v nov direktorij, ki vsebuje eno samo datoteko.
To imenujemo v1 datoteke in jo bomo označili z modro barvo.
Sedaj zaženemo git init
, kar bo ustvarilo repozitorij Git z referenco glave (HEAD), ki kaže na nerojeno vejo master
.
V tem trenutku ima vsebino le drevo delovnega direktorija.
Zdaj želimo potrditi to datoteko, zato uporabimo git add
, da vsebino v delovnem direktoriju kopiramo v indeks.
git add
kopira datoteko v indeksNato zaženemo git commit
, ki sprejme vsebino indeksa in jo shrani kot trajni posnetek, ustvari objekt potrditve, ki kaže na ta posnetek, in posodobi master
, da kaže na to potrditev.
git commit
Če zaženemo git status
, ne bomo videli sprememb, saj so vsa tri drevesa enaka.
Sedaj želimo spremeniti to datoteko in jo potrditi. Gremo skozi enak postopek; najprej spremenimo datoteko v svojem delovnem direktoriju. Imenujmo jo v2 datoteke in jo označimo z rdečo barvo.
Če zdaj zaženemo git status
, bomo videli datoteko v rdeči barvi z napisom »Changes not staged for commit«, ker se ta vnos razlikuje med indeksom in delovnim direktorijem.
Nato zaženemo git add
, da jo damo v področje priprave (v naš indeks).
Če zaženemo git status
, bomo trenutno videli datoteko v zeleni barvi pod »Changes to be committed«, ker se indeks in HEAD razlikujeta — to pomeni, da se naša naslednja predlagana potrditev razlikuje od naše zadnje potrditve.
Na koncu zaženemo git commit
, da zaključimo potrjevanje.
git commit
s spremenjeno datotekoZdaj nam git status
ne bo dal nobenega izpisa, saj so vsa tri drevesa spet enaka.
Preklapljanje vej in kloniranje gresta skozi podoben proces. Ko preklopite na vejo, se spremeni HEAD, da kaže na novo referenco veje, vaš indeks se napolni s posnetkom te potrditve, nato pa se vsebina indeksa kopira v vaš delovni direktorij.
Vloga ponastavitve
Ukaz reset
ima več smisla, če ga gledamo v tem kontekstu.
Za namene teh primerov recimo, da smo spet spremenili datoteko file.txt
in jo tretjič potrdili.
Tako je sedaj videti naša zgodovina:
Sedaj si poglejmo, kaj reset
točno naredi, ko ga pokličemo.
Neposredno spreminja ta tri drevesa na preprost in predvidljiv način.
Izvede do tri osnovne operacije.
1. korak: Premikanje HEAD
Prva stvar, ki jo reset
naredi, je premik tistega, na kar kaže HEAD.
To ni enako spreminjanju samega HEAD (to naredi ukaz checkout
); reset
premakne vejo, na katero kaže HEAD.
To pomeni, da če je HEAD nastavljen na vejo master
(torej se trenutno nahajate na veji master
), bo izvajanje ukaza git reset 9e5e6a4
najprej spremenilo master
, da kaže na 9e5e6a4
.
Ne glede na to, katero obliko reset
z določeno potrditvijo uporabite, je to prva stvar, ki jo bo vedno poskusil narediti.
Z uporabo reset --soft
se bo postopek tam preprosto ustavil.
Sedaj si vzemite trenutek in si oglejte ta diagram ter ugotovite, kaj se je zgodilo: v bistvu se je preklical zadnji ukaz git commit
.
Ko zaženete git commit
, Git ustvari novo potrditev in nanjo premakne vejo, na katero kaže HEAD.
Ko se z ukazom reset
vrnete na HEAD~
(na nadrejeno od HEAD
), premaknete vejo nazaj na prejšnje mesto, pri tem pa ne spremenite indeksa ali delovnega direktorija.
Sedaj lahko posodobite indeks in znova zaženete git commit
, da dosežete to, kar bi naredil git commit --amend
(glejte Spreminjanje zadnje potrditve).
2. korak: Posodobitev indeksa (--mixed
)
Opazite lahko, da boste z zagonom ukaza git status
sedaj videli v zeleni barvi razliko med indeksom in tem, kam kaže novi HEAD.
Naslednja stvar, ki jo bo reset
naredil, je posodobitev indeksa z vsebino posnetka, na katerega sedaj kaže HEAD.
Če določite možnost --mixed
, se bo postopek ukaza reset
ustavil na tem koraku.
To je tudi privzeta možnost, zato če ne navedete nobene možnosti (v tem primeru le git reset HEAD~
), se bo ukaz končal tukaj.
Sedaj si vzemite še eno sekundo, da si ogledate ta diagram in ugotovite, kaj se je zgodilo: še vedno ste preklicali zadnji ukaz commit
, vendar ste tudi premaknili vse spremembe iz indeksa v delovni direktorij.
Vrnili ste se na stanje pred zagonom ukazov git add
in git commit
.
3. korak: Posodobitev delovnega direktorija (--hard
)
Tretja stvar, ki jo bo reset
naredil, je, da bo delovni direktorij videti tako kot indeks.
Če uporabite možnost --hard
, se bo nadaljeval na tej stopnji.
Razmislimo o tem, kaj se je pravkar zgodilo.
Preklicali ste zadnjo potrditev, ukaza git add
in git commit
ter vso delo, ki ste ga opravili v svojem delovnem direktoriju.
Pomembno je opozoriti, da je ta zastavica (--hard
) edini način, da je ukaz reset
nevaren, in eden izmed zelo redkih primerov, ko Git dejansko uniči podatke.
Katerakoli drugačna uporaba ukaza reset
se lahko precej enostavno razveljavi, ne pa možnost --hard
, saj silovito prepiše datoteke v delovnem direktoriju.
V tem posebnem primeru imamo še vedno različico v3 naše datoteke v potrditvi v naši bazi podatkov Git in jo lahko dobimo nazaj s pogledom v naš reflog, vendar bi jo Git še vedno prepisal, če je ne bi potrdili, in postala bi nepopravljivo izgubljena.
Povzetek
Ukaz reset
prepisuje ta tri drevesa v določenem vrstnem redu in se ustavi, ko mu to sporočite:
-
Premakne vejo, na katero kaže HEAD (ustavi se tu, če je izbrana možnost
--soft
). -
Posodobi indeks, da ustreza trenutnemu stanju HEAD-a (ustavi se tu, razen če je izbrana možnost
--hard
). -
Posodobi delovni direktorij tako, da ustreza indeksu.
Ponastavitev s potjo
To zajema obnašanje ukaza reset
v njegovi osnovni obliki, vendar pa mu lahko podate tudi pot, na kateri naj deluje.
Če navedete pot, bo reset
preskočil korak 1 in omejil preostanek svojih dejanj na določeno datoteko ali niz datotek.
To dejansko ima smisel — HEAD je le kazalec in ne morete kazati na del ene potrditve in del druge.
Vendar pa se lahko indeks in delovno okolje delno posodobita, zato reset
nadaljuje s korakoma 2 in 3.
Zato predpostavimo, da zaženemo git reset file.txt
.
Ta oblika (ker niste navedli SHA-1 ali veje in niste navedli --soft
ali --hard
) je kratka oblika git reset --mixed HEAD file.txt
, ki bo:
-
Premaknila vejo, na katero kaže HEAD (preskočeno).
-
Naredi, da indeks izgleda kot HEAD (ustavi se tukaj).
Tako preprosto kopira file.txt
iz HEAD-a v indeks.
To ima praktični učinek dajanja datoteke izven področja priprave.
Če si ogledamo diagram za ta ukaz in razmislimo o tem, kaj naredi git add
, sta si natančno nasprotna.
To je razlog, zakaj nam izhod ukaza git status
predlaga, naj za preklic dajanja datoteke v področje priprave uporabimo ta ukaz (za več informacij glejte razdelek Povrnitev datoteke iz področja priprave).
Enako lahko dosežemo tudi tako, da Gitu ne dovolimo, da smo mislili »povleci podatke iz HEAD«, tako da navedemo specifično potrditev, od koder želimo povleči datoteko.
Tako bi lahko zagnali nekaj podobnega git reset eb43bf file.txt
.
To dejansko naredi enako, kot če bi v delovnem direktoriju vsebino datoteke pripeljali nazaj na v1, na njej uporabili git add
in jo nato spet vrnili na v3 (ne da bi dejansko šli skozi vse te korake).
Če zdaj poženemo git commit
, bo zabeležil spremembo, ki vrne datoteko nazaj na v1, čeprav je dejansko nikoli nismo imeli v svojem delovnem direktoriju.
Zanimivo je tudi omeniti, da kot pri git add
, lahko tudi ukaz reset
sprejme možnost --patch
, da premakne vsebine iz področja priprave po kosih.
Tako lahko izbirate katero vsebino želite pustiti izven področja priprave, ali jo obrniti.
Stiskanje skupaj
Poglejmo, kako lahko s tem novo pridobljenim orodjem naredimo nekaj zanimivega — stisnemo potrdive skupaj (angl. squashing).
Recimo, da imate vrsto potrditev s sporočili, kot so »ups.«, »WIP« in »forgot this file«.
Uporabite lahko reset
, da jih hitro in enostavno združite v eno samo potrditev, kar vas bo naredilo pametnejšega.
V razdelku Stiskanje potrditev skupaj je prikazan še en način, kako to storiti, vendar bo v tem primeru lažje uporabiti reset
.
Recimo, da imate projekt, kjer prva potrditev vsebuje eno datoteko, druga pa je dodala novo datoteko in spremenila prvo, tretja potrditev pa je ponovno spremenila prvo datoteko. Druga potrditev je bilo delo v napredku in ga želite stisniti skupaj.
Za premikanje glavne veje na starejšo potrditev (zadnjo potrditev, ki jo želite obdržati), lahko zaženete ukaz git reset --soft HEAD~2
:
In nato enostavno ponovno poženete git commit
:
Sedaj lahko vidite, da vaša dosegljiva zgodovina, zgodovina, ki bi jo potisnili, zdaj kaže, kot da imate eno potrditev s file-a.txt
v1, nato drugo, ki je spremenila file-a.txt
na v3 in dodala file-b.txt
.
Potrditve z različico datoteke v2 ni več v zgodovini.
Izvlečenje
Končno se morda sprašujete, kakšna je razlika med ukazoma checkout
in reset
.
Podobno kot reset
, checkout
manipulira s tremi drevesi, in je nekoliko drugačen glede na to, ali mu podate pot do datoteke ali ne.
Brez poti
Izvedba git checkout [branch]
je precej podobna izvedbi git reset --hard [branch]
, saj posodobi vsa tri drevesa tako, da so videti kot [branch]
, vendar obstajata dve pomembni razliki.
Prvič, glede na reset --hard
je checkout
varnejši glede delovnega direktorija; preveri, da ne briše datotek, ki so že spremenjene.
Pravzaprav je malce pametnejši od tega — poskuša narediti trivialno združevanje v delovnem direktoriju, zato bodo vse datoteke, ki jih niste spremenili, posodobljene.
reset --hard
pa preprosto nadomesti vse preko celega nabora brez preverjanja.
Druga pomembna razlika je, kako checkout
posodobi HEAD.
Kjer reset
premakne vejo, na katero kaže HEAD, checkout
premakne sam HEAD, da kaže na drugo vejo.
Na primer, recimo, da imamo veji master
in develop
, ki kažeta na različni potrditvi, in smo trenutno na veji develop
(tako da kaže HEAD nanjo).
Če izvedemo git reset master
, se bo develop
sama premaknila na isto potrditev kot master
.
Če pa izvedemo git checkout master
, se develop
ne premakne, premakne se sam HEAD.
HEAD bo sedaj kazal na master
.
V obeh primerih premikamo HEAD, da kaže na potrditev A, vendar je način, kako to storimo, zelo drugačen.
reset
premakne vejo, na katero kaže HEAD, checkout
pa premakne sam HEAD.
git checkout
in git reset
S potmi
Drugi način izvedbe ukaza checkout
je s potjo do datoteke, kar, tako kot pri reset
, ne premakne HEAD-a.
Gre za isto kot git reset [branch] file
, saj posodobi indeks z datoteko v tej potrditvi in prepiše datoteko v delovnem direktoriju.
Gre za popolnoma enako reč, kot je git reset --hard [branch] file
(če bi lahko to izvedli z reset
) — ni varno za delovni direktorij in ne premakne HEAD-a.
Podobno kot pri git reset
in git add
, tudi checkout
sprejme možnost --patch
, s katero lahko izberete, katere vsebine datoteke želite selektivno povrniti po koščkih.
Povzetek
Upamo, da zdaj razumete ukaz reset
in se z njim počutite bolj domače, vendar ste pa verjetno še vedno malo zmedeni glede tega, kako se točno razlikuje od checkout
in si ne morete zapomniti vseh pravil za različne klice.
Tu je plonk listek za ukaze, ki vplivajo na drevesa.
Stolpec HEAD
prebere REF
, če ta ukaz premakne referenco (vejo), na katero kaže HEAD, in HEAD
, če premakne sam HEAD.
Posebno pozornost posvetite stolpcu »Varno za delovni direktorij?« — če piše NE, premislite še enkrat, preden zaženete ta ukaz.
HEAD | Indeks | Delovni direktorij | Varno za delovni direktorij? | |
---|---|---|---|---|
Nivo potrditve |
||||
|
REF |
NE |
NE |
DA |
|
REF |
DA |
NE |
DA |
|
REF |
DA |
DA |
NE |
|
HEAD |
DA |
DA |
DA |
Nivo datoteke |
||||
|
NE |
DA |
NE |
DA |
|
NE |
DA |
DA |
NE |