From 65af0b39b0379cc36c495172f9f0cceafe005b5d Mon Sep 17 00:00:00 2001 From: Martin Vuk Date: Wed, 14 Jan 2026 13:10:02 +0100 Subject: [PATCH] Dodaj slike v tex verzijo --- .gitignore | 10 +- diagrams/branch-move-img.typ | 2 + diagrams/branches-tags-img.typ | 2 + diagrams/commit-history-img.typ | 2 + diagrams/file-graph-img.typ | 2 + diagrams/head-index-img.typ | 2 + diagrams/object-storage-img.typ | 2 + diagrams/object-storage.typ | 6 +- git-obzornik.tex | 672 ++++++++++++++++++++++++++++++++ pripravi_slike.ps1 | 28 ++ 10 files changed, 724 insertions(+), 4 deletions(-) create mode 100644 diagrams/branch-move-img.typ create mode 100644 diagrams/branches-tags-img.typ create mode 100644 diagrams/commit-history-img.typ create mode 100644 diagrams/file-graph-img.typ create mode 100644 diagrams/head-index-img.typ create mode 100644 diagrams/object-storage-img.typ create mode 100644 git-obzornik.tex create mode 100644 pripravi_slike.ps1 diff --git a/.gitignore b/.gitignore index e477c8f..7f8b959 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ *.aux *.log -*.out \ No newline at end of file +*.out +*.bbl +*.blg +*.pdf +*.synctex.gz +*.fls +*.fdb_latexmk +*.png +*.svg \ No newline at end of file diff --git a/diagrams/branch-move-img.typ b/diagrams/branch-move-img.typ new file mode 100644 index 0000000..756d3c0 --- /dev/null +++ b/diagrams/branch-move-img.typ @@ -0,0 +1,2 @@ +#set page(width: auto, height: auto, margin: 5mm) +#include "branch-move.typ" diff --git a/diagrams/branches-tags-img.typ b/diagrams/branches-tags-img.typ new file mode 100644 index 0000000..35be0ed --- /dev/null +++ b/diagrams/branches-tags-img.typ @@ -0,0 +1,2 @@ +#set page(width: auto, height: auto, margin: 5mm) +#include "branches-tags.typ" diff --git a/diagrams/commit-history-img.typ b/diagrams/commit-history-img.typ new file mode 100644 index 0000000..c16c445 --- /dev/null +++ b/diagrams/commit-history-img.typ @@ -0,0 +1,2 @@ +#set page(width: auto, height: auto, margin: 5mm) +#include "commit-history.typ" diff --git a/diagrams/file-graph-img.typ b/diagrams/file-graph-img.typ new file mode 100644 index 0000000..0f99aaa --- /dev/null +++ b/diagrams/file-graph-img.typ @@ -0,0 +1,2 @@ +#set page(width: auto, height: auto, margin: 5mm) +#include "file-graph.typ" diff --git a/diagrams/head-index-img.typ b/diagrams/head-index-img.typ new file mode 100644 index 0000000..feec444 --- /dev/null +++ b/diagrams/head-index-img.typ @@ -0,0 +1,2 @@ +#set page(width: auto, height: auto, margin: 5mm) +#include "head-index.typ" diff --git a/diagrams/object-storage-img.typ b/diagrams/object-storage-img.typ new file mode 100644 index 0000000..2f52cb2 --- /dev/null +++ b/diagrams/object-storage-img.typ @@ -0,0 +1,2 @@ +#set page(width: auto, height: auto, margin: 5mm) +#include "object-storage.typ" \ No newline at end of file diff --git a/diagrams/object-storage.typ b/diagrams/object-storage.typ index 083efef..e9232af 100644 --- a/diagrams/object-storage.typ +++ b/diagrams/object-storage.typ @@ -11,9 +11,9 @@ blabla((0, 0.5), name:) file-object((0, 1.5),"33476f", name:)[bla!] tree-object((2, 0), "5e12fg", name:)[koren] - tree-object((2, 1), "32e4f1", name: )[koren] - commit-object((4, 0), "7e43a1", name: )[Prvi vnos] - commit-object((4, 1), "4ef531", name: )[Popravi bla.txt] + tree-object((2, 1), "32e4f1", name:)[koren] + commit-object((4, 0), "7e43a1", name:)[Prvi vnos] + commit-object((4, 1), "4ef531", name:)[Popravi bla.txt] edge(, , "->") edge(, , "->") edge(, , "->")[starš] diff --git a/git-obzornik.tex b/git-obzornik.tex new file mode 100644 index 0000000..d9c4aac --- /dev/null +++ b/git-obzornik.tex @@ -0,0 +1,672 @@ +\documentclass[a4paper]{article} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[slovene]{babel} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{graphicx} +\usepackage{longtable} +\usepackage{booktabs} +\usepackage{array} +\usepackage{calc} +\usepackage{hyperref} +\usepackage{geometry} +\geometry{a4paper, margin=2.5cm} +\usepackage{pmboxdraw} +\usepackage{newunicodechar} +\newunicodechar{├}{\textSFviii} +\newunicodechar{─}{\textSFx} +\newunicodechar{└}{\textSFii} +\newunicodechar{│}{\textSFxi} +\newtheorem{opomba}{Opomba} +\newcommand{\gitobject}[2]{\texttt{.git/objects/#1/#2}} +\title{Matematični pogled na Git} +\author{Martin Vuk} +\date{\today} +\begin{document} + +\maketitle +\begin{abstract} +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 \emph{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 \emph{zgoščevalne funkcije}, \emph{Merklejeva drevesa} +in \emph{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. +\end{abstract} + +\section{Kaj je Git?} + +\href{https://git-scm.com/}{Git} je kot \textbf{časovni stroj} za +datoteke. Uporabniku omogoča, da vidi \textbf{pretekle različice} +datotek, spreminja datoteke, \textbf{brez skrbi, da bi kaj pokvaril} in +datoteke \textbf{deli z drugimi}. Poleg časovnega stroja je Git +\textbf{razpršeno skladišče datotek}. Omogoča, da datoteke +\textbf{hkrati ureja več uporabnikov} na različnih računalnikih in +kasneje spremembe \textbf{združi}. + +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 +različico. Vse te imformacije dajejo podroben pregled nad zgodovino +sprememb. + +Sisteme, ki omogočajo hranjenje preteklih različic datotek, imenujemo +\href{https://en.wikipedia.org/wiki/Version_control}{sistemi za nadzor +različic} (angl. version control system (VCS)) ali \emph{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 +\href{https://en.wikipedia.org/wiki/Distributed_version_control}{distribuiran +sistem za nadzor različic} (angl. Distributed Version Control System +(DVCS)). + +\begin{opomba} +Git in GitHub nista eno in isto. Ljudje pogosto mešajo Git in GitHub. +Git je program, ki si ga lahko vsakdo namesti in poganja na svojem +računalniku. Program Git je ustvaril Linus Torvalds, da bi lažje +upravljal z izvorno kodo za jedro operacijskega sistema Linux. GitHub je +javno spletišče, ki je namenjeno skladiščenju Git repozitorijev. +\end{opomba} + +V nadaljevanju bomo obravnavali nasledjne teme: + +\begin{itemize} +\item + \emph{Podatkovno skladišče:} Kako Git uporablja + \href{https://sl.wikipedia.org/wiki/Zgo\%C5\%A1\%C4\%8Devalna_funkcija}{zgoščevalno + funkcijo} (angl. hash function)? in + \href{https://en.wikipedia.org/wiki/Merkle_tree}{Merklejeva drevesa} + za hranjenje posnetkov vsebine mape. +\item + \emph{Zgodovina sprememb:} Kako zgodovino predstavimo z + \href{https://en.wikipedia.org/wiki/Directed_acyclic_graph}{usmerjenim + acikličnim grafom}, v katerem so vozlišča različice, povezave pa + povežejo različice z njihovimi neposrednimi predhodniki? +\item + \emph{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? +\end{itemize} + +\section{Podatkovno skladišče} + +Ko ustvarimo nov Git repozitorij, Git ustvari podmapo z imenom +\texttt{.git} z vsemi podatki, ki jih Git potrebuje. Git v mapi +\texttt{.git} hrani različne stvari: + +\begin{itemize} +\item + vsebino datotek, ki smo jih dodali v repozitorij, +\item + drevesno strukturo korenske mape, ki jo hranimo v repozitoriju, +\item + posnetke stanja v različnih trenutkih s podatki o avtoju, datumu in + opisu sprememb, +\item + kazalce na posamezne posnetke stanja. +\end{itemize} + +Git repozitorij je vsaka mapa, ki vsebuje podmapo \texttt{.git} z zgoraj +navedenimi podatki. Podrobnosti o tem, kako Git hrani podatke, si lahko +preberete v knjigi Pro Git \cite{chacon_102_nodate}. + +\section{Zgoščevalna funkcija} + +Git ne shranjuje datotek z običajnimi imeni, ampak za ime uporabi 160 +bitno število (40 mestno število v 16-tiškem zapisu), ki ga izračuna iz +vsebine datoteke. Git za izračun imena uporabi \emph{zgoščevalno +funkcijo}. Naj bo \(B\) množica vseh možnih podatkovnih nizov(besedil), +\(n\)-bitna zgoščevalna funkcija je funkcija +\[H:B \rightarrow \left\{ 0,1,\ldots,2^{n} - 1 \right\},\] ki vsakemu +besedilu \(b\) priredi \(n\)-bitno vrednost \(H(b)\). Vrednosti +zgoščevalne funkcije \(H(b)\) pravimo \emph{zgostitev} vsebine \(b\) +(angl. hash). Git hrani datoteke pod imeni, ki so enaka zgostitvi +vsebine. Kaj pa če imata dve različni vsebini isto zgostitev? Funkcija +\(H\) ni injektivna, saj je množica nizov, bistveno večja od množice +zgostitev. To pomeni, da imata lahko dve različni datoteki enako +zgostitev. Če se to zgodi, rečemo, da pride do \emph{kolizije +zgostitve}. V primeru kolizije zgostitve bi Git shranil le eno datoteko, +za drugo pa bi predpostavil da je že shranjena. Zato je funkcija \(H\) +izbrana tako, da sprememba enega samega bita v besedilu \(b \in B\) +spremeni vrednost \(H(b)\) in je porazdelitev vrednosti \(H(b)\) čim +bližje enakomerni porazdelitvi. To pomeni, da so vse vrednosti \(H(b)\) +približno enako verjetne. Na ta način zmanjšamo verjetnost kolizije( +glej \hyperref[sec_kolizije]{{[}sec\_kolizije{]}}). Verjetnost kolizije +je izjemno majhna, zato Git lahko predpostavi, da je niz \(b\) enolično +določen z njegovo zgostitvijo \(H(b)\). + +Git uporablja \(160\) bitno zgoščevalno funkcijo \emph{SHA1}. Funkcija +SHA1 je posebna implementacija zgoščevalne funkcije, ki se je +uporabljala v kriptografiji\footnote{Leta 2017 so raziskovalci iz CWI + Amsterdam in Google Research našli prvi praktični primer dveh + različnih pdf datotek, ki imata isto SHA1 + zgostitev\cite{stevens_first_2017}. Opisan napad so poimenovali + \emph{SHAttered}. Git je zato z verzijo \texttt{v2.13.0} začel + uporabljati verzijo SHA1, ki je odporna proti napadu \emph{SHAttered}. + Kljub temu razvijalci Gita načrtujejo, da bodo SHA1 postopoma + nadomestili s SHA-256.}. + +Ko datoteko z vsebino \(b\) zabeležimo v Git repozitorij, Git izračuna +zgostitev vsebine \(H(b)\) in jo shrani v datoteko z imenom \(H(b)\) v +\texttt{git/objects}\footnote{V resnici Git shrani vsebino v datoteko z + imenom \(h_{3}h_{4}\ldots h_{40}\) v mapi \(h_{1}h_{2}\), kjer je + \(h_{1}h_{2}h_{3}\ldots h_{40}\) zapis \(H(b)\) v 16-tiškem sistemu. + Datoteka, katere vsebina ima zgostitev \(H(b)\) enako + \texttt{8dd6d4bdaeff93016bd49474b54a911131759648} bo shranjena v + \texttt{.git/objects/8d/d6d4bdaeff93016bd49474b54a911131759648}}. +Vsebina \(b\) je tako vedno dostopna pod imenom, ki je enako njeni +zgostitvi \(H(b)\). Tako dobimo +\href{https://en.wikipedia.org/wiki/Content-addressable_storage}{vsebinsko +naslovljivo shrambo objektov}, ki je ena od bistvenih značilnosti Gita. +Ta način shranjevanja omogoča, da lahko vedno preverimo, če ima +shranjenjena vsebina isto zgostitev, kot je njeno ime. Lahko tudi +shranimo več različic iste datoteke, saj ima vsaka različica drugačno +zgostitev. Zgostitev služi tudi kot kontrola, če je prišlo do kvaritve +podatkov, ki so shranjeni v Git repozitoriju. + +\section{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 mape? Git za to ustvari nov tip objekta +\emph{drevo} (angl. \emph{tree}), ki hrani preprost seznam imen datotek +in naslovov na vsebino datotek v mapi. Naslov na vsebino datoteke \(b\) +je seveda zgostitev vsebine \(H(b)\). Seznam imen datotek in zgostitev +je preprosta tekstovna datoteka, za katero lahko izračunamo zgostitev. +Zgostitev 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 zgostitev +in posledično zgostitev 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. + +\begin{figure} +\centering +\begin{verbatim} +100644 blob 33476f4951afc28d5ac2dc0d42d82f17ac817de2 bla.txt +100644 blob 2ce22b4dc77442103f095503f1205937c1b0fcfc blabla.txt +040000 tree ae247f2a35aadade5863aec2475cf13020304b06 podmapa +\end{verbatim} +\caption{Vsebina mape v Gitu je preprost seznam datotek in podmap ter +zgostitev njihove vsebine} +\end{figure} + +Poglejmo si primer. Denimo, da imamo v naslednjo strukturo datotek in +podmap + +\begin{figure} +\centering +\begin{verbatim} +├── bla.txt (vsebina: bla) +├── blabla.txt (vsebina: blabla) +└── podmapa + └── bla.txt (vsebina: bla) +\end{verbatim} +\caption{Struktura datotek in podmap, ki jo bomo hranili v Gitu.} +\end{figure} +\pagebreak +Git bo shranil naslednje objekte v vsebinsko naslovljivo shrambo: + +\begin{itemize} +\item + vsebino datoteke \texttt{bla.txt} +\begin{verbatim} +bla +\end{verbatim} +v \gitobject{bc}{c1382241e267cf790ca6b3afe9fde6dcf1072f} +\item + vsebino datoteke \texttt{blabal.txt} +\begin{verbatim} +blabla +\end{verbatim} + v \gitobject{2c}{e22b4dc77442103f095503f1205937c1b0fcfc} +\item + seznam datotek v mapi \texttt{podmapa} + +\begin{verbatim} +100644 blob bcc1382241e267cf790ca6b3afe9fde6dcf1072f bla.txt +\end{verbatim} + v \gitobject{ae}{247f2a35aadade5863aec2475cf13020304b06} +\item + seznam datotek v korenski mapi +\begin{verbatim} +100644 blob 33476f4951afc28d5ac2dc0d42d82f17ac817de2 bla.txt +100644 blob 2ce22b4dc77442103f095503f1205937c1b0fcfc blabla.txt +040000 tree ae247f2a35aadade5863aec2475cf13020304b06 podmapa +\end{verbatim} + v \gitobject{47}{3e0bbfc9de64fdca00e611e5666788ddf664ca} +\end{itemize} + +Z uporabo zgostitve kot kazalca na vsebino, Git vsebino mape postavi v +podatkovno strukturo, ki jo matematično lahko opišemo z \emph{usmerjenim +grafom}. Če je vsebina datotek enaka(npr. \texttt{bla.txt} in +\texttt{mapa/bla.txt}), Git shrani le eno kopijo, ki je dostopna v +datoteki \linebreak\texttt{.git/objects/bc/c1382241e267cf790ca6b3afe9fde6dcf1072f}. +Zato datotečno drevo v Gitu ni nujno predstavljeno kot drevo, ampak kot +\emph{usmerjen aciklični graf}. + +\begin{figure} +\centering +\includegraphics[width=0.6\linewidth]{slike/file-graph.pdf} +\caption{Primer datotečnega grafa povezanega z zgostitvami. Zaradi +preglednosti bomo v slikah izpisali le prvih 6 znakov zgostitve.} +\end{figure} + +Posledično lahko vsebino celotne mape opišemo z eno samo zgostitvijo. Če +spremenimo vsebino, ime ali lokacijo datoteke, bo sprememba vplivala na +zgostitev spremenjene vsebine in sprememba bo splavala na površje do +zgostitve za korensko mapo. Zgostitev služi tako kot identifikator +vsebine, kot tudi kot kontrolna vsota, ki omogoča detekcijo sprememb. + +Opomba\\ +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. + +Opomba\\ +Dostop do objekta je mogoč, če poznamo \textbf{zgostitev} njegove +vsebine. To pomeni, da je referenca na posamezen objekt v Gitu preprosto +zgostitev(angl. hash) vsebine tega objekta. Po drugi strani je vsebina +objekta določena z njegovo zgostitvijo. To pomeni, da lahko enostavno +preverimo verodostojnost vsebine, ki je shranjena v Gitu. Git hrani +skladišče objektov v mapi \texttt{.git/objects}. + +\section{Kolizije zgostitev in rojstnodnevni +paradoks}\label{sec_kolizije} + +Git hrani datoteke pod imeni, ki so enaka zgostitvi vsebine. Če imata +dve datoteki z različno vsebino isto zgostitev, Git shrani le eno +datoteko in pride do izgubil podatkov. Git se zanaša na to, da je +verjetnost za to izjemno majhna. Kako bi ocenili to verjetnost? + +Koliko datotek bi morali shraniti v Git, da bi z znatno verjetnostjo +prišlo do kolizije? Vprašanje je povezano z rojstnodnevnim problemom. +Kako velika naj bo skupina ljudi, da bo vsaj \(50\%\) verjetnost, da +imata dve osebi na isti dan rojstni dan? Velikost skupine je +presenetljivo majhna(23), zato rojstnodnevnei problem imenujemo tudi +rojstnodnevni paradoks. Vprašanje zastavimo matematično. Naključno +izberemo \(n < d\) števil iz množice \(\left\{ 1,2,\ldots,h \right\}\), +tako da je vsaka izbira enakomerno porazdeljena. Kolikšna je verjetnost +\(p(n,h)\), da bosta vsaj dve števili enaki? Verjetnost \(p(n,h)\) +izračunamo elementarno z verjetnostjo nasprotnega dogodka: + +\[1 - p(n,h) = \frac{h \cdot (h - 1)\cdots(h - n + 1)}{h^{n}} = \prod_{k = 1}^{n - 1}\left( 1 - \frac{k}{h} \right).\] + +Če izraz logaritmiramo, dobimo +\[\log(1 - p(n,h)) = \sum_{k = 1}^{n - 1}\log(1 - \frac{k}{h}) < - \sum_{k = 1}^{n - 1}\frac{k}{h} = \frac{- \left( n(n - 1) \right)}{2h}.\]\protect\phantomsection\label{eq_log_ocena}{} +Res! Logaritem je konveksna funkcija, zato so vrednosti manjše od +vrednosti na tangenti +\(\log(1 - \frac{k}{h}) = \log(1 - x) < x = \frac{k}{h}\). + +Od tod izpeljemo oceno za \(p(n,h)\) +\[p(n,h) > 1 - e^{\frac{- \left( n(n - 1) \right)}{2h}} \approx 1 - e^{- \frac{n^{2}}{2h}}.\]\protect\phantomsection\label{eq_ocena}{} +Za vrednosti \(1 \ll n \ll h\) je \(1 - e^{- \frac{n^{2}}{2h}}\) tudi +dobra aproksimacija za \(p(n,h)\). + +Da bi odgovorili kako odporna je zgoščevalna funkcija na morebitne +kolizije, moramo rešiti obratno nalogo: največ koliko števil \(n(p,d)\) +lahko izberemo, da bo verjetnost pojava dveh enakih števil manjša od +\(p \in \lbrack 0,1\rbrack\)? Natančen odgovor na to vprašanje ni tako +preprost \cite{brink_probably_2012}. Lahko pa uporabimo oceno +(\hyperref[eq_ocena]{{[}eq\_ocena{]}}) in čez palec ocenimo vrednost +\(n(p,h)\): + +\[\begin{array}{r} + - n^{2} \approx \log(1 - p) \Rightarrow \\ +n(p,h) \approx \sqrt{2h\log(\frac{1}{1 - p})} \approx \sqrt{2h}. +\end{array}\] + +Funkcija \(\sqrt{\log(\frac{1}{1 - p})}\) zelo počasi narašča, ko se +\(p\) približuje \(1\), zato jo lahko zanemarimo. Če je zgoščevalna +funkcija \(160\) bitna, kot na primer SHA1, je +\(n \approx \sqrt{2^{160}} \approx 2^{80}\). Znatna verjetnost, da pride +do kolizije zgostitev, bi se pojavila, ko bi shranili \(2^{80}\) +različnih verzij datotek v Git. Raziskovalci, ki so razvili napad +\emph{SHAttered}, so se posebej potrudili in so potrebovali ``zgolj'' +približno \(2^{63}\) primerov, da so prišli do kolizije. + +\section{Zgodovinski graf sprememb} + +V prejšnjem poglavju smo videli, kako Git hrani vsebino celotne mape in +kako je mogoče do vsebine dostopati če poznamo zgostitvijo korenskega +mape. Zgodovinsko drevo sprememb je preprosta razširitev omenjene +podatkovne strukture. + +\section{Posnetki stanja} + +Osnovna enota v Gitu je \textbf{Vnos} (angl. \textbf{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. Podobno kot objekt tipa \emph{drevo}, je tudi +vnos objekt v vsebinsko naslovljivi shrambi, ki ima določeno +\textbf{zgostitev vnosa}. Zgostitev vnosa je natanko določena z vsebino +shranjenih datotek in metapodatkov vnosa. + +\begin{gitobject}{8dd6d4bdaeff93016bd49474b54a911131759648} +tree 65c47feec7465e80492620a48206793e078702e0 +parent 16f2994757f1213935b8edb9ae7fee3a8e9ec98d +author MV 1765235698 +0100 +committer MV 1765235698 +0100 + +Dodaj bla +\end{gitobject} + +Vsak vnos je povezan s točno določenim posnetekom vsebine korenskega +datotečnega drevesa, ki ga identificira zgostitev. Poleg tega so +posamezni vnosi so povezani v \textbf{usmerjen acikličen graf (DAG)}, ki +predstavlja zgodovino sprememb. Vsak \textbf{vnos} je \textbf{vozlišče} +v grafu. Vsak vnos izhaja iz enega ali več starševskih vnosov. Izjema je +prvi vnos. \textbf{Povezave} v grafu povezujejo vnose z njihovimi +starši. + +\begin{figure} +\centering +\includegraphics[width=0.6\linewidth]{slike/commit-history.pdf} +\caption{Vnosi v Gitu kot usmerjen graf. Vsak vnos(razen prvega) ima +povezavo na vnose iz katerih izhaja.} +\end{figure} + +Git hrani zgodovino sprememb v \emph{vsebinsko naslovljivi shrambi +objektov}, ki hrani tri vrste objektov: + +\begin{itemize} +\item + \texttt{blob}: vsebina datotek, +\item + \texttt{tree}: vsebina mape, +\item + \texttt{commit}: posnetek vsebine v določenem trenutku. +\end{itemize} + +Objekti so poevazni v \emph{usmerjen aciklični graf}. Podgraf na vnosih +določa zgodovino sprememb. Naslovi objektov so \emph{zgostitve} vsebine +objekta, zato je zagotovljena verodostojnost shranjenih podatkov. + +\begin{figure} +\centering +\includegraphics[width=0.6\linewidth]{slike/object-storage.pdf} +\caption{Vsebinsko naslovljiva shramba objektov v Gitu. Naslovi so +zgostitve vsebine. Shramba vsebuje dva vnosa. V prvem vnosu smo dodali +dve datoteki \protect\texttt{bla.txt} in \protect\texttt{blabla.txt}, v +drugem vnosu pa smo spremenili le vsebino datotoeke +\protect\texttt{bla.txt}.} +\end{figure} + +\section{Kazalci: veje in značke} + +Poleg objektov kot so \emph{vnosi}, \emph{posnetki map} in +\emph{posnetki datotek} pozna git še reference. Reference so kazalci z +določenim imenom na posamezen vnos. + +\begin{figure} +\centering +\includegraphics[width=0.6\linewidth]{slike/branches-tags.pdf} +\caption{Veja (angl. branch) ali značka(angl. tag) je preprost kazalec +na posamezen vnos(angl. commit).} +\end{figure} + +Referenc git ne hrani v skladišču objektov, temveč posebej v mapi +\texttt{.git/refs}. Reference vezane na posamezen repozitorij in se +lahko razlikujejo med različnimi kloni določenega repozitorija. + +\textbf{Veja} (angl. \textbf{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. + +\textbf{Značka} (angl. \textbf{tag}) je referenca, ki je statična in se +ne premika več, ko jo enkrat ustvarimo. + +\begin{figure} +\centering +\includegraphics[width=0.6\linewidth]{slike/branch-move.pdf} +\caption{Ko ustvarimo nov vnos, se aktivna veja \protect\texttt{main} +premakne naprej, značka \protect\texttt{v-1.0} pa ostane tam, kjer je +bila.} +\end{figure} + +Opomba\\ +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: +\texttt{main} ali \texttt{master} je navadno glavna veja razvoja, veje z +imeni \texttt{stable}, \texttt{production}, \texttt{development} in +podobno označujejo različne stopnje razvoja programske opreme, veje s +predpono \texttt{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. + +\textbf{HEAD} je posebna referenca, ki kaže na trenutno aktiven vnos. +Vnos, na katerega kaže \emph{HEAD} bo starševski vnos naslednjeg vnosa, +ki ga bomo dodali. + +\begin{figure} +\centering +\includegraphics[width=0.6\linewidth]{slike/head-index.pdf} +\caption{\textbf{HEAD} je referenca na trenutno aktiven vnos. +\emph{Index} vsebuje spremembe, ki bodo zabeležene v naslednjem vnosu.} +\end{figure} + +\section{Povzetek} + +Povzemimo sedaj, kaj smo spoznali o podatkovnem modelu Gita. V vsebinsko +naslovljivi shrambi hrani Git posnetke stanja celotne mape, ki ga vodimo +v repozitoriju skupaj z metapodatki o spremembah. Najpomembnejša pojma +sta: + +\begin{itemize} +\item + \textbf{Vnos} (angl. \textbf{commit}) je posnetek trenutnega stanja + projekta, shranjen kot vozlišče v zgodovinskem grafu, ki vsebuje + posnetek stanja datotek ter metapodatke (avtor, čas, sporočilo). +\item + \textbf{zgostitev vnosa} (angl. \textbf{commit hash}) je 40-mestna + heksadecimalna vrednost, izračunana s SHA-1, ki enolično identificira + vnos na podlagi vsebine posnetka in metapodatkov. +\end{itemize} + +Izven shrambe objektov hrani Git še reference na posamezne vnose. +Poznamo dve vrsti referenc: + +\begin{itemize} +\item + \textbf{Veja} (angl. \textbf{branch}) je premična reference, ki kaže + na določen vnos v zgodovini in se samodejno premakne naprej, ko + dodajamo nove vnose. Veje omogočajo vzporedne razvojne linije ki so + med sabo neodvisne. +\item + \textbf{Oznaka} (angl. \textbf{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. +\item + \textbf{HEAD} je posebna oznaka, ki kaže na trenutno aktiven vnos v + delovni kopiji. +\end{itemize} + +Omenimo še dva pojma, ki jih uporabljamo pri delu z Gitom: + +\begin{itemize} +\item + \textbf{Delovna kopija} (angl. \textbf{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 + (\texttt{HEAD}). Spremembe, ki jih naaredimo na delovni kopiji lahko + zabeležimo v nov vnos. +\item + \textbf{Oddaljen repozitorij} (angl. \textbf{remote}) je povezava(url) + na isti repozitorij na drugem računalniku(ponavadi strežniku), s + katerim lahko izmenjujemo vsebino. +\end{itemize} + +Opomba\\ +Gitov podatkovni model omogoča, da je večina operacij v Gitu obrnljivih. +To pomeni, da lahko repozitorij povrnemo v prejšnje stanje. Običajne +operacije le dodajajo nove vnose in starih ne brišejo. Prav tako se v +zgodovinsko drevo le dodaja nove povezave in starih se ne briše. Zato +daje delo z Gitom uporabniku samozavest, da brez strahu spreminja +vsebino, saj se lahko vedno vrne v času nazaj, kot da bi imel časovni +stroj. + +Nekatere operacije pa tudi brišejo vnose (npr. \texttt{git\ rebase}). +Takim operacijam rečemo, da spreminjajo zgodovino. Uporabniki morajo +biti pri uporabi operacij, ki spreminjajo zgodovino posebej pazljivi, da +česa trajno ne zamočijo. + +\section{Git ukazi kot operacije na grafu} + +Ko smo opremljeni z razumevanjem podatkovnega modela Gita, razložimo kaj +pomenijo posamezne operacije, ki jih Git omogoča. Ukazov ne bom +prevajal, ampak jih bom navedel kot jih pozna program \texttt{git}. + +\section{Checkout} + +Ukaz + +\begin{verbatim} +git checkout referenca +\end{verbatim} + +spremeni datoteke v delovni kopiji tako, da se ujemajo z vnosom, na +katerega kaže referenca. Poleg tega prestavi oznako \texttt{HEAD} na +isti vnos. Če je referenca veja, jo nastavi, kot aktivno vejo. Če je +referenca oznaka ali zgostitev vnosa, priedmo v stanje brez aktivne veje +(angl. \emph{deteached HEAD}). + +\section{Commit} + +Ukaz + +\begin{verbatim} +git commit -m "Sporočilo za vnos" +\end{verbatim} + +ustvari nov vnos, ki kaže na stanje v čakalnici (angl. staging area ali +index). V zgodovinskem grafu ustvari novo vozlišče, ki je povezano s +prejšnjim vnosom. Poleg tega prestavi aktivno vejo in oznako +\texttt{HEAD} na novo ustvarjeni vnos. + +\section{Add} + +Ukaz + +\begin{verbatim} +git add bla.txt +\end{verbatim} + +doda vsebino spremenjene datoteke \texttt{bla.txt} v čakalnico. Ukaz ne +spreminja zgodovinskega grafa, pač pa doda novo vsebino in datotečna +drevesa, ki vsebujejo spremembe v shrambo objektov. Vsebina čakalnice bo +zabeležena v naslednjem vnosu. + +\section{Pull} + +Ukaz + +\begin{verbatim} +git pull +\end{verbatim} + +pobere vsebino(objekte in reference) iz oddaljenega repozitorija in +uskladi lokalno vejo z oddaljeno. Shrambi objektov se preprosto doda +nove objekte, ki so v oddaljeni veji. Če je lokalna veja prednik +oddaljene, se lokalna veja enostavno prestavi, da kaže na isti vnos, kot +oddaljena veja. V nasprotnem primeru, mora uporabnik posredovati in +razrešiti morebitne konflikte. + +\section{Push} + +Ukaz + +\begin{verbatim} +git push +\end{verbatim} + +potisne novo vsebino na oddaljeni repozitorij. Push deluje obratno kot +\texttt{pull}. Ukaz je uspešno izveden le, če je oddaljena veja prednica +lokalne veje in ni konflikotov. + +\section{Fetch} + +Ukaz + +\begin{verbatim} +git fetch +\end{verbatim} + +pobere novo vsebino (vnose, veje in oznake) iz oddaljenega repozitorija. +Pri tem ne more priti do konfliktov, ker git preprosto doda nove objekte +v shrambo in obstoječih objektov nikakor ne spreminja. Oddaljenim vejam +in oznakam preprosto doda predpono z imenom oddaljenega repozitorija. + +\section{Reset} + +Ukaz + +\begin{verbatim} +git reset referenca +\end{verbatim} + +spremeni kam kaže trenutno izbrana veja. Ukaz ne spremeni zgodovinskega +drevesa, ampak le to, na kateri vnos kaže trenutno izbrana veja. + +\section{Merge} + +Ukaz + +\begin{verbatim} +git merge referenca +\end{verbatim} + +ustvari nov vnos, ki združi dve ločeni veji v eno (trenutno izbrano in +referenco). Nov vnos ima dva starša: vnos na katerega kaže trenutna veja +in vnos, na katerega kaže referenca. Če pride do konfliktov, jih mora +uporabnik sam razrešiti, preden se ustvari nov vnos. + +\section{Rebase} + +Ukaz + +\begin{verbatim} +git rebase referenca +\end{verbatim} + +prestavi vnose v trenutno izbrani veji tako, da so potomci vnosa, na +katerega kaže referenca. Med ukazi, ki smo jih spoznali, je ta ukaz +edini, ki lahko povzroči izgubo podatkov. Običajno ukazi le dodajajo +nove vnose in prestavljajo reference. Zato je večina ukazov v Gitu +varna, v smislu, da jih lahko kasneje prekličemo in pridemo nazaj na +prejšnje stanje. Ukaz \texttt{rebase} pa spremeni zgodovino in ga ne +moremo preklicati, saj trenutne vnose nadomesti z novimi in stare vnose +pobriše\footnote{Obstaja enostaven način, da tudi \texttt{rebase} lahko + prekličemo. Na zadnji vnos, ki ga želimo prestaviti preprosto + postavimo novo referenco(vejo ali oznako). To povzroči, da se stari + vnosi ne pobrišejo tudi, ko se izvede ukaz \texttt{rebase}.}. + +\section{Zaključek} + +Spoznali smo, kako deluje Git in s katere matematičnime pojme uporablja +za model. Opis dela z Gitom presega namen tega dokumenta, zato vas raje +usmerim na uradno dokumentacijo: + +{\url{https://git-scm.com/cheat-sheet}} + +Pri pisanju tega članka sem sevada uporabljal Git. V +\href{https://git.fri.uni-lj.si/martin.vuk/git-intro}{javno dostopnem +repozitoriju} \cite{vuk_git-intro_nodate} si lahko ogledate celotno +zgodovino nastajanja tega članka. + +Pri pripravi dokumenta sem uporabil Gemini 3. Vse odgovore sem preveril +in uredil po svoje. + +\bibliographystyle{plain} +\bibliography{reference} +\end{document} diff --git a/pripravi_slike.ps1 b/pripravi_slike.ps1 new file mode 100644 index 0000000..108274b --- /dev/null +++ b/pripravi_slike.ps1 @@ -0,0 +1,28 @@ +$diagramsDir = "diagrams" +$outputDir = "slike" + +# Create output directory if it doesn't exist +if (!(Test-Path -Path $outputDir)) { + New-Item -ItemType Directory -Path $outputDir | Out-Null +} + +# Get all wrapper .typ files in the diagrams directory (files ending in -img.typ) +$files = Get-ChildItem -Path $diagramsDir -Filter "*-img.typ" + +foreach ($file in $files) { + # Remove -img from the output filename to match the desired naming convention + $baseName = $file.BaseName -replace "-img$", "" + $outputFile = Join-Path -Path $outputDir -ChildPath ($baseName + ".pdf") + Write-Host "Compiling $($file.Name) to $outputFile..." + + # Run typst compile with necessary flags + # --root . : Allow access to files in the project root (like definicije.typ) + # --ppi 300 : Increase resolution for better quality + typst compile --root . --ppi 300 $file.FullName $outputFile + + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to compile $($file.Name)" + } +} + +Write-Host "All diagrams compiled."