Zamenjaj direktorij z mapo

This commit is contained in:
Martin Vuk 2026-01-07 19:34:06 +01:00
parent c6dc1988e0
commit aec037c0dd

View file

@ -24,7 +24,7 @@ Martin Vuk
#v(2em) #v(2em)
#abstract[ #abstract[
Git je program, ki omogoča vodenje zgodovine različic datotek v nekem direktoriju. V glavnem se uporablja za upravljanje z izvorno kodo pri razvoju računalniških programov. Mnogi med nami pa ga uporabljajo tudi pri pisanju besedil v _LaTeX_-u. Poleg tega, da Git hrani zgodovino sprememb, tudi omogoča da več ljudi hkrati sodeluje pri urejanju istih datotek. Git je program, ki omogoča vodenje zgodovine različic datotek v neki mapi(direktoriju). V glavnem se uporablja za upravljanje z izvorno kodo pri razvoju računalniških programov. Mnogi med nami pa ga uporabljajo tudi pri pisanju besedil v _LaTeX_-u. Poleg tega, da Git hrani zgodovino sprememb, tudi omogoča da več ljudi hkrati sodeluje pri urejanju istih datotek.
Ogledali si bomo, kako Git deluje. Opisali bomo, kako Git uporabi _zgoščevalne funkcije_, _Merklejeva drevesa_ in _usmerjene aciklične grafe_, da shrani zgodovino različic in omogoči hkratno urejanje vsebine. Matematični model, ki ga Git uporablja je v resnici zelo preprost in njegovo razumevanje nas lahko reši marsikatere zagate, ki nastane med njegovo uporabo. Ogledali si bomo, kako Git deluje. Opisali bomo, kako Git uporabi _zgoščevalne funkcije_, _Merklejeva drevesa_ in _usmerjene aciklične grafe_, da shrani zgodovino različic in omogoči hkratno urejanje vsebine. Matematični model, ki ga Git uporablja je v resnici zelo preprost in njegovo razumevanje nas lahko reši marsikatere zagate, ki nastane med njegovo uporabo.
] ]
@ -35,7 +35,7 @@ sprememinja datoteke, *brez skrbi, da bi kaj pokvaril* in datoteke *deli z drugi
Git *razpršeno skladišče datotek*. Omogoča, da datoteke *hkrati ureja več uporabnikov* na različnih računalnikih in Git *razpršeno skladišče datotek*. Omogoča, da datoteke *hkrati ureja več uporabnikov* na različnih računalnikih in
kasneje spremembe *združi*. kasneje spremembe *združi*.
Git hrani vsebino direktorija z datotekami in celotno zgodovino različic datotek iz preteklosti. Git hrani vsebino mape 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 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. različico. Vse te imformacije dajejo podroben pregled nad zgodovino sprememb.
@ -53,7 +53,7 @@ Zato je Git #link("https://en.wikipedia.org/wiki/Distributed_version_control")[d
V nadaljevanju bomo obravnavali nasledjne teme: 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] - _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. in #link("https://en.wikipedia.org/wiki/Merkle_tree")[Merklejeva drevesa] za hranjenje posnetkov vsebine mape.
- _Zgodovina sprememb:_ Kako zgodovino predstavimo z #link("https://en.wikipedia.org/wiki/Directed_acyclic_graph")[usmerjenim acikličnim grafom], - _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. 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 - _Reference_: Kako preproste reference (kazalci) na vsebino omogočajo bliskovito
@ -61,13 +61,13 @@ V nadaljevanju bomo obravnavali nasledjne teme:
= Podatkovno skladišče = Podatkovno skladišče
Ko ustvarimo nov Git repozitorij, Git ustvari direktorij z imenom `.git`, ki vsebuje vse podatke, ki jih Git potrebuje. Git v mapi `.git` hrani različne stvari: Ko ustvarimo nov Git repozitorij, Git ustvari podmapo z imenom `.git`, ki vsebuje vse podatke, ki jih Git potrebuje. Git v mapi `.git` hrani različne stvari:
- vsebino datotek, s ki smo jih dodali v repozitorij - vsebino datotek, s ki smo jih dodali v repozitorij
- drevesno strukturo direktorija - drevesno strukturo mape
- posnetke stanja v rezličnih trenutkih s podatki o avtoju, datumu in opisu sprememb - posnetke stanja v rezličnih trenutkih s podatki o avtoju, datumu in opisu sprememb
- kazalce na posamezne posnetke stanja - kazalce na posamezne posnetke stanja
Git repozitorij je vsak direktorij, ki vsebuje poddirektorij `.git` z zgoraj navedenimi podatki. Git repozitorij je vsaka mapa, ki vsebuje podmapo `.git` z zgoraj navedenimi podatki.
Podrobnosti o tem lahko preberete v knjigi Pro Git Podrobnosti o tem lahko preberete v knjigi Pro Git
#cite(<chacon_102_nodate>, supplement: [pog. 10.2]). #cite(<chacon_102_nodate>, supplement: [pog. 10.2]).
@ -91,10 +91,10 @@ Vsebina $b$ je tako vedno dostopna pod imenom $H(b)$. Tako dobimo #link("https:/
== Datotečna drevesa == Datotečna drevesa
V vsebinsko naslovljivo shrambo objektov lahko shranimo vsebino datotek in njihovih prejšnjih različic. A kako ohranimo informacijo o imenu datotek in drevesni strukturi direktorija? Git za to ustvari nov tip objekta _drevo_ (angl. _tree_), ki hrani preprost seznam imen datotek in naslovov na vsebino datotek v direktoriju. Naslov na vsebino datoteke $b$ je seveda zgoščena vrednost vsebine $H(b)$. Seznam imen datotek in zgoščenih vrednosti je preprosta tekstovna datoteka, za katero lahko izračunamo zgoščeno vrednost. Zgoščena vrednost datotečnega drevesa natanko določa tako imena datotek, kot tudi vsebino datotek, ki so vsebovane v direktoriju. Če se katerakoli datoteka ali ime datoteke v direktoriju spremeni, se bo spremnila tudi V vsebinsko naslovljivo shrambo objektov lahko shranimo vsebino datotek in njihovih prejšnjih različic. A kako ohranimo informacijo o imenu datotek in drevesni strukturi mape? Git za to ustvari nov tip objekta _drevo_ (angl. _tree_), ki hrani preprost seznam imen datotek in naslovov na vsebino datotek v mapi. Naslov na vsebino datoteke $b$ je seveda zgoščena vrednost vsebine $H(b)$. Seznam imen datotek in zgoščenih vrednosti je preprosta tekstovna datoteka, za katero lahko izračunamo zgoščeno vrednost. Zgoščena vrednost datotečnega drevesa natanko določa tako imena datotek, kot tudi vsebino datotek, ki so vsebovane v mapi. Če se katerakoli datoteka ali ime datoteke v mapi spremeni, se bo spremnila tudi
njena zgoščena vrednost in posledično zgoščena vrednost za drevo. Poleg posameznih datotek, lahko drevo vsebuje tudi poddrevesa. Tako lahko rekurzivno ustvarimo drevesno podatkovno strukturo, ki zajema direktorij z datotekami in poddirektoriji v poljubni globini. njena zgoščena vrednost in posledično zgoščena vrednost za drevo. Poleg posameznih datotek, lahko drevo vsebuje tudi poddrevesa. Tako lahko rekurzivno ustvarimo drevesno podatkovno strukturo, ki zajema mapo z datotekami in podmapami v poljubni globini.
#figure(caption: [Vsebina direktorija v Gitu je preprost seznam datotek in poddirektorijev in zgoščenih vrednosti njihove vsebine], #figure(caption: [Vsebina mape v Gitu je preprost seznam datotek in podmap in zgoščenih vrednosti njihove vsebine],
raw(align: left, block: true, raw(align: left, block: true,
" "
100644 blob bcc1382241e267cf790ca6b3afe9fde6dcf1072f bla.txt 100644 blob bcc1382241e267cf790ca6b3afe9fde6dcf1072f bla.txt
@ -102,7 +102,7 @@ raw(align: left, block: true,
040000 tree 605f479464bebe4f7250ace49bab48e72855f84a podmapa 040000 tree 605f479464bebe4f7250ace49bab48e72855f84a podmapa
")) "))
Poglejmo si primer. Denimo, da imamo v naslednjo strukturo datotek in poddirektorijev Poglejmo si primer. Denimo, da imamo v naslednjo strukturo datotek in podmap
#figure(raw(block: true, #figure(raw(block: true,
" "
├── bla.txt (vsebina: bla) ├── bla.txt (vsebina: bla)
@ -116,16 +116,16 @@ Git bo shranil naslednje objekte v vsebinsko naslovljivo shrambo:
#git-object("bcc1382241e267cf790ca6b3afe9fde6dcf1072f", "bla") #git-object("bcc1382241e267cf790ca6b3afe9fde6dcf1072f", "bla")
- vsebino datoteke `blabal.txt`: - vsebino datoteke `blabal.txt`:
#git-object("2ce22b4dc77442103f095503f1205937c1b0fcfc", "blabla") #git-object("2ce22b4dc77442103f095503f1205937c1b0fcfc", "blabla")
- seznam datotek v direktoriju `mapa`: - seznam datotek v mapi `mapa`:
#git-object("e8cc593eddfb9cfdafb4f9c46ab7f5a05ea00b2b", #git-object("e8cc593eddfb9cfdafb4f9c46ab7f5a05ea00b2b",
"100644 blob bcc1382241e267cf790ca6b3afe9fde6dcf1072f bla.txt "100644 blob bcc1382241e267cf790ca6b3afe9fde6dcf1072f bla.txt
100644 blob 2ce22b4dc77442103f095503f1205937c1b0fcfc blabla.txt") 100644 blob 2ce22b4dc77442103f095503f1205937c1b0fcfc blabla.txt")
- seznam datotek v korenskem direktoriju: - seznam datotek v korenski mapi:
#git-object("1331d77b31e40d6b470706b195f21244bb32cf21", #git-object("1331d77b31e40d6b470706b195f21244bb32cf21",
"100644 blob bcc1382241e267cf790ca6b3afe9fde6dcf1072f bla.txt "100644 blob bcc1382241e267cf790ca6b3afe9fde6dcf1072f bla.txt
040000 tree e8cc593eddfb9cfdafb4f9c46ab7f5a05ea00b2b mapa") 040000 tree e8cc593eddfb9cfdafb4f9c46ab7f5a05ea00b2b mapa")
Git z uporabo zgoščene vrednosti kot kazalca na vsebino, vsebino direktorija postavi v podatkovno strukturo, ki jo matematično lahko opišemo z _usmerjenim acikličnim grafom_. Ko je vsebina Git z uporabo zgoščene vrednosti kot kazalca na vsebino, vsebino mape postavi v podatkovno strukturo, ki jo matematično lahko opišemo z _usmerjenim acikličnim grafom_. Ko je vsebina
datotek enaka(npr. `bla.txt` in `mapa/bla.txt`), Git shrani le eno kopijo, ki je dostopna v datoteki `.git/objects/bc/c1382241e267cf790ca6b3afe9fde6dcf1072f`. Zato datotečno drevo v Gitu ni nujno predstavljeno kot drevo, ampak kot usmerjen aciklični graf. datotek enaka(npr. `bla.txt` in `mapa/bla.txt`), Git shrani le eno kopijo, ki je dostopna v datoteki `.git/objects/bc/c1382241e267cf790ca6b3afe9fde6dcf1072f`. Zato datotečno drevo v Gitu ni nujno predstavljeno kot drevo, ampak kot usmerjen aciklični graf.
#let bla(coord, ..args) = file-object(coord, "bcc138", ..args)[bla] #let bla(coord, ..args) = file-object(coord, "bcc138", ..args)[bla]
@ -145,7 +145,7 @@ diagram(
} }
)) ))
Posledično lahko celotno vsebino direktorija opišemo z eno samo zgoščeno vrednostjo. Če spremenimo vsebino, ime ali lokacijo datoteke, bo sprememba vplivala na zgoščeno vrednost spremenjene vsebine in sprememba bo splavala na površje do zgoščene vrednosti za korenski direktorij. Zgoščena vrednost služi tako kot identifikator vsebine, kot tudi kot kontrolna vsota, ki omogoča detekcijo sprememb. Posledično lahko vsebino celotne mape opišemo z eno samo zgoščeno vrednostjo. Če spremenimo vsebino, ime ali lokacijo datoteke, bo sprememba vplivala na zgoščeno vrednost spremenjene vsebine in sprememba bo splavala na površje do zgoščene vrednosti za korensko mapo. Zgoščena vrednost služi tako kot identifikator vsebine, kot tudi kot kontrolna vsota, ki omogoča detekcijo sprememb.
#note[ #note[
Podatkovna struktura objektov v Gitu je podobna Merklejevim drevesom. Razlika je v tem, da Gita hrani le eno kopijo datotek z identično vsebino, zato dobimo usmerjen aciklični graf in ne drevesa. Postopek je podoben veriženju blokov, ki se uporablja v kriptovalutah. Podatkovna struktura objektov v Gitu je podobna Merklejevim drevesom. Razlika je v tem, da Gita hrani le eno kopijo datotek z identično vsebino, zato dobimo usmerjen aciklični graf in ne drevesa. Postopek je podoben veriženju blokov, ki se uporablja v kriptovalutah.
@ -154,12 +154,12 @@ Posledično lahko celotno vsebino direktorija opišemo z eno samo zgoščeno vre
#note[ #note[
Dostop do objekta je mogoč, če poznamo *zgoščeno vrednost* njegove vsebine. To pomeni, da je referenca na 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 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`. 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 mapi `.git/objects`.
] ]
= Zgodovinski graf sprememb = Zgodovinski graf sprememb
V prejšnjem poglavju smo videli, kako Git hrani vsebino direktorija in kako je mogoče do vsebine dostopati če poznamo zgoščeno vrednost korenskega direktorija. Zgodovinsko drevo sprememb je preprosta razširitev omenjene podatkovne strukture. V prejšnjem poglavju smo videli, kako Git hrani vsebino celotne mape in kako je mogoče do vsebine dostopati če poznamo zgoščeno vrednost korenskega mape. Zgodovinsko drevo sprememb je preprosta razširitev omenjene podatkovne strukture.
== Posnetki stanja == Posnetki stanja
@ -176,7 +176,7 @@ committer MV <mv@example.com> 1765235698 +0100
Dodaj bla Dodaj bla
"), "),
caption: [Primer vnosa v Gitu. Vnos vsebuje zgoščeno vrednost posnetka direktorija(`tree`), zgoščeno vrednost caption: [Primer vnosa v Gitu. Vnos vsebuje zgoščeno vrednost posnetka mape(`tree`), zgoščeno vrednost
starševskega vnosa (`parent`) in metapodatke. Tudi sam vnos je natančno določen z zgoščeno vrednostjo.], starševskega vnosa (`parent`) in metapodatke. Tudi sam vnos je natančno določen z zgoščeno vrednostjo.],
) )
@ -210,7 +210,7 @@ Vsak vnos je povezan s točno določenim posnetekom vsebine korenskega datotečn
Git hrani zgodovino sprememb v _vsebinsko naslovljivi shrambi objektov_, ki hrani tri vrste objektov: Git hrani zgodovino sprememb v _vsebinsko naslovljivi shrambi objektov_, ki hrani tri vrste objektov:
- `blob`: vsebina datotek, - `blob`: vsebina datotek,
- `tree`: vsebina direktorijev, - `tree`: vsebina mape,
- `commit`: posnetek vsebine v določenem trenutku. - `commit`: posnetek vsebine v določenem trenutku.
Objekti so poevazni v _usmerjen aciklični graf_. Podgraf na vnosih določa zgodovino sprememb. Naslovi objektov so _zgoščene vrednosti_ vsebine objekta, zato je zagotovljena verodostojnost shranjenih podatkov. Objekti so poevazni v _usmerjen aciklični graf_. Podgraf na vnosih določa zgodovino sprememb. Naslovi objektov so _zgoščene vrednosti_ vsebine objekta, zato je zagotovljena verodostojnost shranjenih podatkov.
@ -243,7 +243,7 @@ Objekti so poevazni v _usmerjen aciklični graf_. Podgraf na vnosih določa zgod
= Kazalci: veje in značke = 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. Poleg objektov kot so _vnosi_, _posnetki map_ in _posnetki datotek_ pozna git še reference. Reference so kazalci z določenim imenom na posamezen vnos.
#figure( #figure(
diagram(node-stroke: 0.5pt, diagram(node-stroke: 0.5pt,
@ -264,7 +264,7 @@ Poleg objektov kot so _vnosi_, _posnetki direktorijev_ in _posnetki datotek_ poz
caption: [Veja (angl. branch) ali značka(angl. tag) je preprost kazalec na posamezen vnos(angl. commit). ] 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. Referenc git ne hrani v skladišču objektov, temveč posebej v mapi `.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. *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.
@ -325,7 +325,7 @@ Vse te pomene damo vejam ljudje, ki sodelujemo v nekem Git repozitoriju. Za Git
== Povzetek == Povzetek
Povzemimo sedaj, kaj smo spoznali o podatkovnem modelu Gita. Povzemimo sedaj, kaj smo spoznali o podatkovnem modelu Gita.
V vsebinsko naslovljivi shrambi hrani Git posnetke stanja direktorija, ki ga vodimo v repozitoriju skupaj z metapodatki o spremembah. Najpomembnejša pojma sta: V vsebinsko naslovljivi shrambi hrani Git posnetke stanja celotne mape, ki ga vodimo v repozitoriju skupaj z metapodatki o spremembah. Najpomembnejša pojma sta:
- *Vnos* (angl. *commit*) je posnetek trenutnega stanja projekta, shranjen kot vozlišče v zgodovinskem grafu, ki vsebuje posnetek stanja datotek ter metapodatke (avtor, čas, sporočilo). - *Vnos* (angl. *commit*) je posnetek trenutnega stanja projekta, shranjen kot vozlišče v zgodovinskem grafu, ki vsebuje posnetek stanja 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 vsebine posnetka in metapodatkov. - *Zgoščena vrednost vnosa* (angl. *commit hash*) je 40-mestna heksadecimalna vrednost, izračunana s SHA-1, ki enolično identificira vnos na podlagi vsebine posnetka in metapodatkov.
@ -334,7 +334,7 @@ Izven shrambe objektov hrani Git še reference na posamezne vnose. Poznamo dve v
- *Oznaka* (angl. *tag*) je statična referenca, 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. - *Oznaka* (angl. *tag*) je statična referenca, 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.
- *HEAD* je posebna oznaka, ki kaže na trenutno aktiven vnos v delovni kopiji. - *HEAD* je posebna oznaka, ki kaže na trenutno aktiven vnos v delovni kopiji.
Omenimo še dva pojma, ki jih uporabljamo pri delu z Gitom: Omenimo še dva pojma, ki jih uporabljamo pri delu z Gitom:
- *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. - *Delovna kopija* (angl. *workout copy*) je mapa v kateri 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 isti repozitorij na drugem računalniku(ponavadi strežniku), s katerim lahko izmenjujemo vsebino. - *Oddaljen repozitorij* (angl. *remote*) je povezava(url) na isti repozitorij na drugem računalniku(ponavadi strežniku), s katerim lahko izmenjujemo vsebino.
@ -433,7 +433,3 @@ Pri pisanju tega članka sem sevada uporabljal Git. V
Pri pripravi dokumenta sem uporabil Gemini 3. Vse odgovore sem preveril in uredil po svoje. Pri pripravi dokumenta sem uporabil Gemini 3. Vse odgovore sem preveril in uredil po svoje.
#bibliography("reference.bib") #bibliography("reference.bib")
Sledi še skica, ki povzame vse komponente Git repozitorija.
#set page(numbering: none)
#include "git-figure.typ"