#set page("a4", margin: 20mm) #set heading(numbering: "1.") #show heading: block.with(below: 1.5em) #set text(lang: "sl") #show link: set text(blue) #import "@preview/fletcher:0.5.8" as fletcher: diagram, edge, node #import fletcher.shapes: chevron, house, pill #let note(content) = rect(stroke: 0.5pt, width: 100%, fill: green.lighten(50%), content) #include "git-figure.typ" #align(center)[ #set text(size:2em) *Git za matematike* ] #v(2em) Naučili se bomo, *kako Git deluje*. Spoznali bomo, da so v ozadju Gita *vsebinsko naslovljiva shramba podatkov*, *Merklejeva drevesa* in *usmerjeni aciklični grafi*. *Cilj:* Razumeti _logiko_ Gita. Ko razumemo, kaj je v ozadju, lahko operacije, kot so `merge`, `rebase` in `reset` preporsto razložimo s preoblikovanjem grafa in premikanjem kazalcev po grafu. *Čas branja:* 30 min = Kaj je Git? #link("https://git-scm.com/")[Git] je kot *časovni stroj* za datoteke. Uporabniku omogoča, da vidi *pretekle različice* datotek, sprememinja datoteke, *brez skrbi, da bi kaj pokvaril* in datoteke *deli z drugimi*. Poleg časovnega stroja je Git *razpršeno skladišče datotek*. Omogoča, da datoteke *hkrati ureja več uporabnikov* na različnih računalnikih in kasneje spremembe *združi*. Git hrani vsebino direktorija z datotekami in celotno zgodovino različic datotek iz preteklosti. Za vsako različico hrani Git zapis o avtorju, datumu in opis sprememb, ki so nastale v primerjavi s predhodno različico. Vse te imformacije dajejo podroben pregled nad zgodovino sprememb. #note[ Sisteme, ki omogočajo hranjenje preteklih različic datotek, imenujemo #link("https://en.wikipedia.org/wiki/Version_control")[sistemi za nadzor različic] (angl. version control system (VCS)) ali _sistemi za upravljanje z izvorno kodo_ (angl. Source Code Management (SCM)). Poleg nadzora različic Git omogoča hkratno spreminjanje datotek več uporabnikov na različnih računalnikih. Zato je Git #link("https://en.wikipedia.org/wiki/Distributed_version_control")[distribuiran sistem za nadzor različic] (angl. Distributed Version Control System (DVCS)). ] V nadaljevanju bomo obravnavali nasledjne teme: - _Podatkovno skladišče:_ Kako Git uporablja #link("https://sl.wikipedia.org/wiki/Zgo%C5%A1%C4%8Devalna_funkcija")[zgoščevalno funkcijo] in #link("https://en.wikipedia.org/wiki/Merkle_tree")[Merklejeva drevesa] za hranjenje posnetkov vsebine direktorija. - _Zgodovina sprememb:_ Kako zgodovino predstavimo z #link("https://en.wikipedia.org/wiki/Directed_acyclic_graph")[usmerjenim acikličnim grafom], v katerem so vozlišča različice in ki povezuje različice z njihovimi neposrednimi predhodniki. - _Reference_: Kako preproste reference (kazalci) na vsebino omogočajo bliskovito preklaplanje med različicami in preprečijo popolno zmešnjavo, ko več ljudi hkrati spreminja iste datoteke. = Podatkovno skladišče == Git repozitorij Git repozitorij je direktorij v katerem je poddirektorij `.git`, ki vsebuje vso zgodovino sprememb in ostale podatke, ki jih Git potrebuje. == Vnos: posnetek stanja Osnovna enota v Gitu je *vnos* (angl. *commit*). Vnos je posnetek stanja zabeleženih datotek v trenutku, ko je bil ustvarjen. Poleg vsebine datotek vsak vnos vsebuje še metapodatke o avtorju, datumu vnosa in opisom sprememb. Vsakemu vnosu je prirejena *zgoščena vrednost vnosa* (angl. *hash*), ki je 40-mestna heksadecimalna vrednost, izračunana s SHA-1, in je natanko določena z vsebino shranjenih datotek in metapodatkov vnosa. #note[Git obravnava podatke v repozitoriju kot *posnetke stanja* in ne zgolj kot zaporedje *sprememb*. To je ena glavnih razlik med Gitom in predhodnimi sistemi za upravljanje različic (glej #link("https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F")[Kaj je Git?]).] Vnose in vsebino datotek hrani Git v #link("https://git-scm.com/book/en/v2/Git-Internals-Git-Objects")[skladišču objektov]. Do objektov v skladišču lahko dostopamo, če poznamo njihovo _zgoščeno vrednost_. Objekti, ki jih Git hrani v skladišču so *vnosi*, *posnetki direktorijev* in *posnetki posameznih datotek*. #figure( table( columns: 1, [*zgoščena vrednost*: 8dd6d4bdaeff93016bd49474b54a911131759648], ``` tree 65c47feec7465e80492620a48206793e078702e0 parent 16f2994757f1213935b8edb9ae7fee3a8e9ec98d author MV 1765235698 +0100 committer MV 1765235698 +0100 Dodaj bla ```, stroke: 1pt, align: left, ), caption: [Primer vnosa v Gitu. Vnos vsebuje zgoščeno vrednost posnetka direktorija(`tree`), zgoščeno vrednost starševskega vnosa (`parent`) in metapodatke. Tudi sam vnos je natančno določen z zgoščeno vrednostjo.], ) Posnetki direktorijev so v Gitu posebne vrste objekti tipa `tree`. Vsebujejo zgoščene vrednosti in metapodatke o datotekah in direktorijih, ki jih vsebuje. #figure( table( columns: 1, stroke: 1pt, [*zgoščena vrednost*: `d934342ca420dd0d9828782c7103103f2922d2a6`], ``` 100644 blob 76018072e09c5d31c8c6e3113b8aa0fe625195ca bar.txt 100644 blob ba0e162e1c47469e3fe4b393a8bf8c569f302116 foo.txt 040000 tree 3b8bfca88b2cc4127ce5909eb3a7395e8b5f2b6a podmapa ```, ), caption: [Primer posnetka direktorija v Gitu (objekt tipa `tree`). Posnetek vsebuje zgoščene vrednosti datotek in direktorija, ki jih vsebuje. Uporaba zgoščenih vrednosti natančno določa vsebino posnetka direktorija.], ) #note[ Skladišča objektov v Gitu je #link("https://en.wikipedia.org/wiki/Content-addressable_storage")[skladišče vsebinsko naslovljivih objektov]. Dostop do objekta je mogoč, če poznamo *zgoščeno vrednost* njegove vsebine. To pomeni, da je referenca na posamezen objekt v Gitu preprosto zgoščena vrednost(angl. hash) vsebine tega objekta. Po drugi strani je vsebina objekta določena z njegovo zgoščeno vrednostjo. To pomeni, da lahko enostavno preverimo verodostojnost vsebine, ki je shranjena v Gitu. Git hrani skladišče objektov v direktoriju `.git/objects`. ] = Zgodovinski graf sprememb Posamezni vnosi so povezani v *usmerjen acikličen graf (DAG)*, ki predstavlja zgodovino sprememb. Vsak *vnos* je *vozlišče* v grafu. Vsak vnos izhaja iz enega ali več starševskih vnosov. Izjema je prvi vnos. *Povezave* v grafu povezujejo vnose z njihovimi starši. #figure( diagram(node-stroke: 1pt, node-shape: pill, { let (Ah, Bh, Ch, Dh, Eh, Fh, Gh) = ("d93434", "2ca420", "dd0d98", "28782c", "710310", "3f2922", "d2a671") let (A, B, C, D, E, F, G) = ((0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (2, 1), (3, 1)) node(A, raw(Ah)) node(B, raw(Bh)) node(C, raw(Ch)) node(D, raw(Dh)) node(E, raw(Eh)) node(F, raw(Fh)) node(G, raw(Gh)) edge(B, A, "->") edge(C, B, "->") edge(D, C, "->") edge(E, D, "->") edge(G, F, "->") edge(F, B, "->") edge(D, F, "->") }), caption: [Vnosi v Gitu kot usmerjen graf. Vsak vnos(razen prvega) ima povezavo na vnose iz katerih izhaja.], ) = Kazalci: veje in značke Poleg objektov kot so _vnosi_, _posnetki direktorijev_ in _posnetki datotek_ pozna Git še reference. Reference so kazalci z določenim imenom na posamezen vnos. #figure( diagram(node-stroke: 0.5pt, { node((2, -1), [main], shape: chevron, name:
) node((-1, 0), [`e23d19`], shape: pill, name: ) node((0, 0), [`3943eb`], shape: pill, name: ) node((1, 0), [`98ff21`], shape: pill, name: ) node((2, 0), [`4e96a1`], shape: pill, name: ) node((0, 1), [v-1.0], shape: chevron.with(dir: left), name: ) edge(, , "->") edge(, , "->") edge(, , "->") edge(
, , "->") edge(, , "->") }), caption: [Veja (angl. branch) ali značka(angl. tag) je preprost kazalec na posamezen vnos(angl. commit). ], ) Referenc Git ne hrani v skladišču objektov, temveč posebej v direktoriju `.git/refs`. Zato so reference vezane na posamezen repozitorij in se lahko razlikujejo med različnimi kloni določenega repozitorija. *Veja* (angl. *branch*) je posebne vrste referenca, ki se premika, ko dodajamo nove vnose. Vsakič ko ustvarimo nov vnos, se trenutno aktivna veja premakne na novo ustvarjeni vnos. *Značka* (angl. *tag*) je referenca, ki je statična in se ne premika več, ko jo enkrat ustvarimo. #figure( diagram(node-stroke: 0.5pt, { node((1, -1), [main], shape: chevron, name: , stroke: (dash: "dotted")) node((-1, 0), [`e23d19`], shape: pill, name: ) node((0, 0), [`3943eb`], shape: pill, name: ) node((1, 0), [`98ff21`], shape: pill, name: ) node((2, 0), [`4e96a1`], shape: pill, name: , stroke: blue) node((2, -1), [main], shape: chevron, name:
) node((1, 1), [v-1.0], shape: chevron, name: ) edge(, , "->") edge(, , "->") edge(, , "->", stroke: blue) edge(, , "->", stroke: (dash: "dotted")) edge(, , "->") edge(
, , "->") }), caption: [Ko ustvarimo nov vnos, se aktivna veja `main` premakne naprej, značka `v-1.0` pa ostane tam, kjer je bila. ], ) #note[ Veje in značke nimajo v Gitu nobenega posebnega pomena, razen tega, da so reference na vnose. Pomen posamenznih vej je stvar dogovora med uporabniki. Tako se pogosto uporablja različne veje za različne namene: `main` ali `master` je navadno glavna veja razvoja, veje z imeni `stable`, `production`, `development` in podobno označujejo različne stopnje razvoja programske opreme, veje s predpono `feature-` označujejo razvoj novih funkcionalnosti. Vse te pomene damo vejam ljudje, ki sodelujemo v nekem Git repozitoriju. Za Git so vse veje in značke zgolj preprosti kazalci na določen vnos. ] *HEAD* je posebna referenca, ki kaže na trenutno aktiven vnos. Vnos, na katerega kaže _HEAD_ bo starševski vnos naslednjeg vnosa, ki ga bomo dodali. #figure( diagram(node-stroke: 0.5pt, { node((-1, 0), [`e23d19`], shape: pill, name: ) node((0, 0), [`3943eb`], shape: pill, name: ) node((1, 0), [`98ff21`], shape: pill, name: ) node((2, 0), [`4e96a1`], shape: pill, name: , stroke: (dash: "dotted")) node((1, -1), [main], shape: chevron, name:
) node((1, 1), [HEAD], shape: chevron, name: ) node((2, 1), [index], shape: rect, name: , stroke: (dash: "dotted")) edge(, , "->") edge(, , "->") edge(, , "->", stroke: (dash: "dotted")) edge(, , "->", stroke: (dash: "dotted")) edge(, , "->") edge(
, , "->") }), caption: [*HEAD* je referenca na trenutno aktiven vnos/vejo.], ) == Delo z Git Opis dela z Gitom presega namen tega dokumenta. Zato vas raje preusmerimo na uradno dokumentacijo: #align(center, text(size: 1.5em)[https://git-scm.com/cheat-sheet]) == Povzetek Samostalniki: - *Vnos* (angl. *commit*) je posnetek trenutnega stanja projekta, shranjen kot vozlišče v zgodovinskem grafu (DAG), ki vsebuje spremembe datotek ter metapodatke (avtor, čas, sporočilo). - *Zgoščena vrednost vnosa* (angl. *commit hash*) je 40-mestna heksadecimalna vrednost, izračunana s SHA-1, ki enolično identificira vnos na podlagi njegove vsebine. - *Veja* (angl. *branch*) je premična oznaka, ki kaže na določen vnos v zgodovini in se samodejno premakne naprej, ko dodajamo nove vnose. Veje omogočajo vzporedne razvojne linije z različnimi spremembami. - *Oznaka* (angl. *tag*) je statična oznaka, ki trajno kaže na določen vnos. Za razliko od veje se oznaka, nikoli ne premika samodejno, zato se uporablja predvsem za označevanje pomembnih točk v zgodovini, kot so izdaje ali stabilne verzije. - *Delovna kopija* (angl. *workout copy*) je direktorij v katerem urejamo datoteke, ki jih nato vnesemo v Git. V delovni kopiji imajo na začetku datoteke isto vsebino kot je vsebina trenutno aktivnega vnosa (`HEAD`). Spremembe, ki jih naaredimo na delovni kopiji lahko zabeležimo v nov vnos. - *Oddaljen repozitorij* (angl. *remote*) je povezava(url) na oddaljen repozitorij, s katerim izmenjujemo vsebino. Glagoli (akcije): - *Checkout* prenese vsebino vnosa v delovno kopijo: `git checkout neka-veja` - *Commit* ustvari nov vnos: `git commit -m 'Sporočilo'` - *Add* doda vsebino, ki bo v naslednjem vnosu: `git add dodaj_me.txt` - *Pull* poberi vsebino iz oddaljenega repozitorija in uskladi lokalno vejo z oddaljeno: `git pull` - *Push* potisni lokalne vnose na oddaljeni repozitorij in uskladi oddaljeno vejo z lokalno: `git push` - *Fetch* pobere nove vnose, veje in oznake iz oddaljenega repozitorija: `git fetch` - *Reset* spremeni kam kaže trenutno izbrana veja: `git reset a239f9e91` - *Merge* ustvari nov vnos, ki združi dve ločeni veji v eno: `git merge main` - *Rebase* prestavi vnose v trenutno izbrani veji na izbran vnos: `git rebase main` Opis dela z Gitom presega namen tega dokumenta. Zato vas raje preusmerimo na uradno dokumentacijo: #align(center, text(size: 1.5em)[https://git-scm.com/cheat-sheet]) Pri pripravi dokumenta sem uporabil Gemini 3. Vse odgovore sem preveril in uredil po svoje. Sledi še skica, ki povzame vse komponente Git repozitorija. #include "git-figure.typ"