14. diel - Git - Vnútorná štruktúra - Dokončenie
V predchádzajúcej lekcii, Git - Vnútorná štruktúra, sme sa pozreli na vnútornú štruktúru Gitu. Ponorili sme sa do detailov spôsobu úschovy commitov a vykonávaných zmien v súboroch vykonaných Gitom.
V dnešnom tutoriáli Git dokončíme zoznámenie s
vnútornou štruktúrou Gitu detailnejším preskúmaním objektov typu
blob, tree, commit a tag.
Následne si vysvetlíme, ako Git uchováva názvy
súborov.
Opäť si všetky príkazy vyskúšame v našom naklonovanom
repozitári Laravel z lekcie Git – Základy –
Dokončenie. Otvoríme terminál MinTTY a pomocou príkazu
cd laravel sa do repositára presunieme.
Typy objektov
Už vieme, že vnútorná štruktúra Gitu je tvorená z objektov typu
blob, tree, commit a tag.
Tieto objekty sú v Gite na seba takto naviazané:
Objekty blob, tree,
commit a tag sme si predstavili v lekcii Git -
Vnútorná štruktúra.
Teraz si jednotlivé objekty popíšeme a vysvetlíme si, ako Git uchováva súbory.
Objekt typu commit
Commit je iba textovým súborom, ktorý prešiel kompresiou, dostal hash a
bol uložený v úložisku objektov. Obsahuje metadáta, ako sú informácie o
autorovi, commiterovi,
dátume vytvorenia commitu a commit správe.
Na zobrazenie obsahu alebo typu ľubovoľného objektu v úložisku je možné
použiť nízkoúrovňový príkaz git s názvom
cat-file vo formátoch:
- git cat-file <hash of the commit> -t,
- git cat-file <hash of the commit> -p.
Obe si teraz vyskúšame 😀
Príkaz
git cat-file <hash of the commit> -t
Teraz teda potrebujeme hash nejakého commitu. Pre ten nebudeme chodiť
ďaleko, ale použijeme náš hash
61f09d5980757dc0a9c05570d24584714b7cd635, s ktorým sme pracovali v
lekcii Git -
Vnútorná štruktúra.
Zadáme teda príkaz
git cat-file 61f09d5980757dc0a9c05570d24584714b7cd635 -t, ktorým
získame typ objektu:
MINGW64:/c/mygit/laravel/.git IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $ git cat-file 61f09d5980757dc0a9c05570d24584714b7cd635 -t commit IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $
Príkaz
git cat-file <hash of the commit> -p
S tým istým hashom spustíme príkaz
git cat-file 61f09d5980757dc0a9c05570d24584714b7cd635 -p, ktorým
získame výpis obsahu commitu:
MINGW64:/c/mygit/laravel/.git IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $ git cat-file 61f09d5980757dc0a9c05570d24584714b7cd635 -p tree 2992d926d6f3495b3b04b88564a1a0fc958d5696 parent 700444ac9735f2a393116705951511421061458d parent 53c4ef4ea87f4d7169a8fa0b74aff591b3508bd8 author ictdemy <[email protected]> 1703077311 +0100 committer ictdemy <[email protected]> 1703077311 +0100 Fix collision when merging branches IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $
Vidíme, že náš commit obsahuje:
- metadáta o commite ako informácie o strome
(
tree), - rodičovské commity,
- autora,
- commitera,
- samotnú správu ku commitu.
Objekt typu tree
tree alebo strom je objekt používaný na ukladanie
zložiek v našom projekte. Strom môže ukazovať na iné stromy a
vytvárať tak úplnú hierarchiu súborov a podpriečinkov.
Každý commit ukazuje na stromový objekt, ktorý v jednej snímke zachytáva stav úložiska v čase vykonania commitu. Tento snímok je verzia projektu, ktorú ukladáme do našej histórie Gitu.
Pozrieme sa, ako taký strom vyzerá. Spustite príkaz
git cat-file <hash of the commit> -t pre hash stromu
(tree) 2992d926d6f3495b3b04b88564a1a0fc958d5696:
MINGW64:/c/mygit/laravel/.git IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $ git cat-file 2992d926d6f3495b3b04b88564a1a0fc958d5696 -t tree IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $
Získame typ objektu tree.
Pre ten istý hash stromu ešte spustíme príkaz
git cat-file <hash of the commit> -p, ktorým získame
výpis súborov obsiahnutých v strome:
MINGW64:/c/mygit/laravel/.git IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $ git cat-file 2992d926d6f3495b3b04b88564a1a0fc958d5696 -p ... 100644 blob 8f0de65c560259bd171d746d12aa187f666893a3 .editorconfig 100644 blob ea0665b0a60cfaafaa7b2c80992a0e406700e1a2 .env.example 100644 blob fcb21d396d657f597ef8b6729f73d89b0a871c9b .gitattributes ... 100644 blob 2c95e74d918d0ea0aef057d2ee97536521101c72 README.md ... 040000 tree a9b549189653697bdcc2597e2a81e93fae10cea6 storage 040000 tree 49a71909565d8572e9d915c039b0fab49d0f4a1a tests 100644 blob 421b5695627db43c022947cfc7c0ecce6b9689be vite.config.js IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $
Vidíme, že pre každý riadok z objektu stromu Git zaznamenáva:
- oprávnenie,
- typ objektu,
- hash objektu,
- názov súboru.
Názvy súborov sú riadené objektom stromu, nie samotnými súbormi. Neskôr si vysvetlíme, prečo to tak je.
Objekt typu blob
Objekty blob obsahujú binárne alebo textové dáta
súborov. Ide o čisté dáta bez informácií o súborovom názve,
ceste alebo akýchkoľvek metadátach, ktoré by identifikovali samotný
súbor.
Bloby reprezentujú konkrétnu verziu súboru v danom okamihu, a preto sú kľúčové pre sledovanie zmien v rámci projektu. Každá zmena vykonaná v súbore vytvára novú verziu blobu. Bloby umožňujú Gitu efektívne ukladať obsah súborov vrátane ich histórie.
Teraz sa na taký blob pozrieme. Spustite príkaz
git cat-file <hash of the commit> -t pre hash súboru
README.md:
MINGW64:/c/mygit/laravel/.git IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $ git cat-file 2c95e74d918d0ea0aef057d2ee97536521101c72 -t blob IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $
Získame typ objektu blob. Pre ten istý hash spustíme príkaz
git cat-file s parametrom -p:
MINGW64:/c/mygit/laravel/.git IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $ git cat-file 2c95e74d918d0ea0aef057d2ee97536521101c72 -p The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). Added text 1 Added text 2 Editing a file on the 10.x branch Editing a file on the feature branch ... IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $
Vidíme, že sme získali výpis obsahu súboru README.md.
Objekt typu tag
tag čiže značka predstavuje špeciálny
odkaz používaný na označenie commitov v
histórii repozitára. Je to statický odkaz na konkrétny commit, ktorý
následne nemení svoju hodnotu. Akonáhle je pre určitý commit tag
vytvorený, jeho hodnota zostáva nemenná. Tagy slúžia na označenie
špecifických bodov v histórii repozitára. Vytvorené tagy sú uložené v
priečinku tags/ vnútri zložky refs/.
Poďme si preskúmať nejaký tag 😀 Najprv sa ale vrátime späť do
koreňového adresára .git/ príkazom cd ... Tagy sú
uložené v priečinku refs/tags/. Presunieme sa tam príkazom
cd refs/tags/:
MINGW64:/c/mygit/laravel/.git IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git (GIT_DIR!) $ cd refs/tags/ IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git/refs/tags (GIT_DIR!) $
Spustite príkaz ls, ktorým získame výpis
tagov v repozitári:
MINGW64:/c/mygit/laravel/.git/refs/tags IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git/refs/tags (GIT_DIR!) $ ls annotated_tag easy_tag IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git/refs/tags (GIT_DIR!) $
Získajme hash tagu annotated_tag príkazom
cat annotated_tag:
MINGW64:/c/mygit/laravel/.git/refs/tags IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git/refs/tags (GIT_DIR!) $ cat annotated_tag 04a272f847c916d9f3ebe7070be57e60142f0ab8 IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git/refs/tags (GIT_DIR!) $
Keď máme hash, zistíme typ objektu príkazom:
MINGW64:/c/mygit/laravel/.git/refs/tags IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git/refs/tags (GIT_DIR!) $ git cat-file 04a272f847c916d9f3ebe7070be57e60142f0ab8 -t tag IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel/.git/refs/tags (GIT_DIR!) $
Získame potvrdenie, že annotated_tag je objekt typu
tag:
MINGW64:/c/mygit/laravel/.git/refs/tags
tag
Týmto sme preskúmali objekty typu blob, tree,
commit a tag. Môžeme sa teda pustiť do ďalšej
časti, v ktorej si vysvetlíme, ako Git uchováva názvy
súborov.
Názvy súborov
V tejto kapitole pochopíme, prečo Git uchováva názvy súborov v objekte
typu tree (strom), a nie v type blob. Poďme na to
😀
Najprv sa vrátime späť do koreňového adresára laravel/
príkazom cd ../... Začneme tým, že si vytvoríme dva nové
commity. Spustíme nasledujúce príkazy, ktoré vytvoria:
- prvý commit s názvom súboru
test_file.txta obsahomTest file, - zložku
tasks/, - druhý commit s názvom súboru
file.txta s obsahomTest fileumiestnenom v priečinkutasks/.
Kód je nasledujúci:
MINGW64:/c/mygit/laravel IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ echo "Test file" > test_file.txt IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git add . IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git commit -m "Created new test file" [10.x a0cac287] New test file created 1 file changed, 1 insertion(+) create mode 100644 test_file.txt IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ mkdir tasks IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ echo "Test file" > ./tasks/file.txt IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git add . IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git commit -m "Tasks folder created" [10.x 0c52e84c] Tasks folder created 1 file changed, 1 insertion(+) create mode 100644 tasks/file.txt IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $
Spustíme príkaz git show, aby sme získali hash
posledného commitu:
MINGW64:/c/mygit/laravel IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git show commit 9d75672de3f87202b615435d3a5ebbe55d4f99ec (HEAD -> 10.x) Author: ictdemy <[email protected]> Date: Thu Dec 21 14:30:51 2023 +0100 Tasks folder created diff --git a/tasks/file.txt b/tasks/file.txt new file mode 100644 index 00000000..2d750b67 --- /dev/null +++ b/tasks/file.txt @@ -0,0 +1 @@ +Test file IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $
Hash sme získali. Spustíme ním teda príkaz
git cat-file 9d75672de3f87202b615435d3a5ebbe55d4f99ec -p, aby sme
získali výpis obsahu commitu:
MINGW64:/c/mygit/laravel IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git cat-file 9d75672de3f87202b615435d3a5ebbe55d4f99ec -p tree f53345c1ed5beaf290ee8edf4881c5a09f14226b parent ec4c318d68c305e42f32f2832cc8507b371f237f author ictdemy <[email protected]> 1703165451 +0100 committer ictdemy <[email protected]> 1703165451 +0100 Tasks folder created IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $
Dostali sme výpis obsahu commitu. Vidíme, že tento commit obsahuje
nadradený rodičovský objekt parent, ktorým je predchádzajúci
commit.
Okrem prvého commitu obsahuje každý commit v Gite odkaz
parent na predchádzajúci commit.
Aby sme sa pozreli do objektu tree, spustíme príkaz
git cat-file <hash of the commit> -p s hashom
predchádzajúceho commitu:
MINGW64:/c/mygit/laravel IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git cat-file f53345c1ed5beaf290ee8edf4881c5a09f14226b -p 100644 blob 8f0de65c560259bd171d746d12aa187f666893a3 .editorconfig 100644 blob ea0665b0a60cfaafaa7b2c80992a0e406700e1a2 .env.example ... 040000 tree 8229fefca7d57f5c87adeef4e35dffa79bb691a6 tasks 100644 blob 2d750b67d34524994ba425d168d5ed2576c11492 test_file.txt 040000 tree 49a71909565d8572e9d915c039b0fab49d0f4a1a tests 100644 blob 421b5695627db43c022947cfc7c0ecce6b9689be vite.config.js IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $
Získali sme výpis obsahu objektu. Ako môžeme vidieť,
strom obsahuje súbor test_file.txt s hashom
2d750b67d34524994ba425d168d5ed2576c11492 z predchádzajúceho
commitu. Teraz obsahuje objekt tree s hashom
8229fefca7d57f5c87adeef4e35dffa79bb691a6.
Zobrazme si obsah tohto stromu, teda hash zložky tasks/, týmto
príkazom:
MINGW64:/c/mygit/laravel IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git cat-file 8229fefca7d57f5c87adeef4e35dffa79bb691a6 -p 100644 blob 2d750b67d34524994ba425d168d5ed2576c11492 file.txt IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $
Spustíme príkaz git cat-file <hash of the commit> -p na
zobrazenie obsahu súboru test_file.txt s jeho hashom
2d750b67d34524994ba425d168d5ed2576c11492 (pozri vyššie):
MINGW64:/c/mygit/laravel IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ git cat-file 2d750b67d34524994ba425d168d5ed2576c11492 -p Test file IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $
Príkaz nám vypísal jeho obsah, teda Test file.
Záver
Teraz vidíme, že hash súboru file.txt je rovnaký ako hash
súboru test_file.txt, hoci sú to rôzne súbory na iných
miestach. Git totiž rozpoznal, že oba súbory majú presne rovnaký obsah. A
preto sa rozhodol vytvoriť iba jeden blob a
použiť rovnakú referenciu dvakrát, namiesto toho, aby
vytvoril dva identické objekty.
Príkaz hash-object
Poďme si ešte náš záver potvrdiť nízkoúrovňovým príkazom
hash-object na rovnakom obsahu Test file oboch
vyššie uvedených súborov. Príkaz vezme časť obsahu a vráti pre neho hash
kľúč.
Spustite nasledujúci príkaz hash-object na vytvorenie hashu
Test file:
MINGW64:/c/mygit/laravel IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $ echo "Test file" | git hash-object --stdin 2d750b67d34524994ba425d168d5ed2576c11492 IctDemy@DESKTOP-ADEVTG4 MINGW64 /c/mygit/laravel (10.x) $
Ak sa nám zobrazí chyba, použijeme príkaz
printf "Test file" | git hash-object --stdin.
Získali sme hash 2d750b67d34524994ba425d168d5ed2576c11492 pre
reťazec Test file. To znamená, že ak vytvoríme ďalší súbor
.txt s obsahom Test file, nový commit bude odkazovať
na rovnaký blob s rovnakým
hashom.
Git spracováva objekty vytvorené v databáze tak efektívne, že používa
objekty blob zakaždým, keď je obsah rovnaký. Nezáleží na
tom, či ide o iný súbor vytvorený v inom priečinku. To je dôvod, prečo
sú názvy súborov uložené v stromoch. Toto
rozhodnutie umožňuje systému Git spracovávať odkazy na rovnaký
objekt blob s rôznymi názvami
súborov.
V ďalšej lekcii, Git - Grafické užívateľské rozhranie Git GUI, si predstavíme grafické užívateľské rozhranie Git GUI. Ukážeme si, ako v ňom vytvoriť commit a spravovať vetvy.
