Lekce 14 - Git - Vnitřní struktura - Dokončení
V minulé lekci, Git - Vnitřní struktura, jsme se podívali na vnitřní strukturu Gitu. Ponořili jsme se do detailů způsobu úschovy commitů a vykonávaných změn v souborech provedených Gitem.
V dnešním Git tutoriálu dokončíme seznámení s
vnitřní strukturou Gitu detailnějším prozkoumáním objektů typu
blob
, tree
, commit
a tag
.
Následně si vysvětlíme, jak Git uchovává názvy
souborů.
Všechny příkazy si opět vyzkoušíme v našem naklonovaném
repozitáři laravel
z lekce Git - Základy -
Dokončení. Otevřeme terminál MinTTY
a pomocí příkazu
cd laravel
se do repozitáře přesuneme.
Typy objektů
Již víme, že vnitřní struktura Gitu je tvořená z objektů typu
blob
, tree
, commit
a tag
.
Tyto objekty jsou v Gitu na sebe takto navázány:
Objekty blob
, tree
,
commit
a tag
jsme si představili v lekci Git -
Vnitřní struktura.
Nyní si jednotlivé objekty popíšeme a vysvětlíme si, jak Git uchovává soubory.
Objekt typu commit
Commit je pouze textovým souborem, který prošel kompresí, obdržel hash a
byl uložen v úložišti objektů. Obsahuje metadata, jako jsou informace o
autorovi, commiterovi, datu
vytvoření commitu a commit zprávě. Pro zobrazení obsahu
nebo typu libovolného objektu v úložišti lze použít nízkoúrovňový
příkaz git
s názvem cat-file
ve formátech:
git cat-file <hash commitu> -t
,git cat-file <hash commitu> -p
.
Oba si nyní vyzkoušíme 😀
Příkaz
git cat-file <hash commitu> -t
Nyní tedy potřebujeme hash nějakého commitu. Pro ten nebudeme chodit
nikam daleko, ale použijeme náš hash
61f09d5980757dc0a9c05570d24584714b7cd635
, se kterým jsme pracovali
v lekci Git -
Vnitřní struktura.
Zadáme tedy příkaz
git cat-file 61f09d5980757dc0a9c05570d24584714b7cd635 -t
, kterým
získáme typ objektu:
MINGW64:/c/mujgit/laravel/.git ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $ git cat-file 61f09d5980757dc0a9c05570d24584714b7cd635 -t commit ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $
Příkaz
git cat-file <hash commitu> -p
S týmž hashem spustíme příkaz
git cat-file 61f09d5980757dc0a9c05570d24584714b7cd635 -p
, kterým
získáme výpis obsahu commitu:
MINGW64:/c/mujgit/laravel/.git ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $ git cat-file 61f09d5980757dc0a9c05570d24584714b7cd635 -p tree 2992d926d6f3495b3b04b88564a1a0fc958d5696 parent 700444ac9735f2a393116705951511421061458d parent 53c4ef4ea87f4d7169a8fa0b74aff591b3508bd8 author itnetwork <[email protected]> 1703077311 +0100 committer itnetwork <[email protected]> 1703077311 +0100 Oprava kolize při sloučení větví ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $
Vidíme, že náš commit obsahuje:
- metadata o commitu jako informace o stromu (tree),
- rodičovské commity,
- autora,
- commitera,
- samotnou zprávu ke commitu.
Objekt typu tree
tree
neboli strom je objekt používaný k ukládání
složek v našem projektu. Strom může ukazovat na jiné stromy a
vytvářet tak úplnou hierarchii souborů a podsložek.
Každý commit ukazuje na stromový objekt, který v jednom snímku zachycuje stav úložiště v době provedení commitu. Tento snímek je verzí projektu, kterou ukládáme do naší historie Gitu.
Podíváme se, jak takový strom vypadá. Spusťme příkaz
git cat-file <hash commitu> -t
pro hash stromu (tree)
2992d926d6f3495b3b04b88564a1a0fc958d5696
:
MINGW64:/c/mujgit/laravel/.git ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $ git cat-file 2992d926d6f3495b3b04b88564a1a0fc958d5696 -t tree ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $
Získáme typ objektu tree
.
Spusťme ještě pro tentýž hash stromu příkaz
git cat-file <hash commitu> -p
, kterým získáme
výpis souborů obsažených ve stromu:
MINGW64:/c/mujgit/laravel/.git ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/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 ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $
Vidíme, že pro každý řádek z objektu stromu Git zaznamenává:
- oprávnění,
- typ objektu,
- hash objektu,
- název souboru.
Názvy souborů jsou řízeny objektem stromu, nikoli soubory samotnými. Později si vysvětlíme, proč tomu tak je.
Objekt typu blob
blob
objekty obsahují binární nebo textová data
souborů. Jde o čistá data bez informací o souborovém názvu,
cestě nebo jakýchkoli metadatech, které by identifikovaly samotný
soubor.
Bloby reprezentují konkrétní verzi souboru v daném okamžiku, a proto jsou klíčové pro sledování změn v rámci projektu. Každá změna provedená v souboru vytváří novou verzi blobu. Bloby umožňují Gitu efektivně ukládat obsah souborů včetně jejich historie.
Nyní se na takový blob podíváme. Spusťme příkaz
git cat-file <hash commitu> -t
pro hash souboru
./README.md
:
MINGW64:/c/mujgit/laravel/.git ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $ git cat-file 2c95e74d918d0ea0aef057d2ee97536521101c72 -t blob ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $
Získáme typ objektu blob
. Pro tentýž hash spusťme příkaz
git cat-file
s parametrem -p
:
MINGW64:/c/mujgit/laravel/.git ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/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). Přidaný text 1 Přidaný text 2 Editace souboru na větvi 10.x Editace souboru na větvi feature ... ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $
Vidíme, že jsme získali výpis obsahu souboru README.md
.
Objekt typu tag
tag
čili značka představuje speciální
odkaz používaný k označení commitů v
historii repozitáře. Je to statický odkaz na konkrétní commit, který
následně nemění svou hodnotu. Jakmile je pro určitý commit tag vytvořen,
jeho hodnota zůstává neměnná. Tagy slouží k označení specifických
bodů v historii repozitáře. Vytvořené tagy jsou uložené ve složce
tags/
uvnitř složky refs/
.
Pojďme si zkusit prozkoumat nějaký tag 😀 Nejprve se ale vrátíme zpět
do kořenového adresáře .git/
příkazem cd ..
.
Tagy jsou uloženy ve složce refs/tags/
. Přesuneme se tam
příkazem cd refs/tags/
:
MINGW64:/c/mujgit/laravel/.git ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git (GIT_DIR!) $ cd refs/tags/ ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git/refs/tags (GIT_DIR!) $
Spusťme příkaz ls
, kterým získáme výpis
tagů v repozitáři:
MINGW64:/c/mujgit/laravel/.git/refs/tags ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git/refs/tags (GIT_DIR!) $ ls anotovany_tag lehky_tag ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git/refs/tags (GIT_DIR!) $
Získejme hash tagu anotovany_tag
příkazem
cat anotovany_tag
:
MINGW64:/c/mujgit/laravel/.git/refs/tags ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git/refs/tags (GIT_DIR!) $ cat anotovany_tag 04a272f847c916d9f3ebe7070be57e60142f0ab8 ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git/refs/tags (GIT_DIR!) $
Když máme hash, zjistěme typ objektu příkazem:
MINGW64:/c/mujgit/laravel/.git/refs/tags ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git/refs/tags (GIT_DIR!) $ git cat-file 04a272f847c916d9f3ebe7070be57e60142f0ab8 -t tag ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel/.git/refs/tags (GIT_DIR!) $
Získáme potvrzení, že anotovany_tag
je objekt typu
tag
:
MINGW64:/c/mujgit/laravel/.git/refs/tags
tag
Tímto jsme dokončili naše zkoumání objektů typu blob
,
tree
, commit
a tag
. Můžeme se tedy
pustit do další části, ve které si vysvětlíme, jak Git uchovává
názvy souborů.
Názvy souborů
V této kapitole pochopíme, proč Git uchovává názvy souborů v objektu
typu tree
(strom), a nikoli v typu blob
. Pojďme na to
😀
Nejprve se vrátíme zpět do kořenového adresáře laravel/
příkazem cd ../..
. Začneme tím, že si vytvoříme dva nové
commity. Spustíme následující příkazy, které vytvoří:
- první commit s názvem souboru
testovaci_soubor.txt
a obsahemTestovaci soubor
, - složku
tasks/
, - druhý commit s názvem souboru
soubor.txt
a s obsahemTestovaci soubor
umístěném ve složcetasks/
.
Kód je následující:
MINGW64:/c/mujgit/laravel ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ echo "Testovaci soubor" > testovaci_soubor.txt ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git add . ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git commit -m "Vytvořen nový testovací soubor" [10.x a0cac287] Vytvořen nový testovací soubor 1 file changed, 1 insertion(+) create mode 100644 testovaci_soubor.txt ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ mkdir tasks ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ echo "Testovaci soubor" > ./tasks/soubor.txt ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git add . ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git commit -m "Vytvořena složka tasks" [10.x 0c52e84c] Vytvořena složka tasks 1 file changed, 1 insertion(+) create mode 100644 tasks/soubor.txt ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $
Spusťme příkaz git show
, abychom získali hash
posledního commitu:
MINGW64:/c/mujgit/laravel ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git show commit 9d75672de3f87202b615435d3a5ebbe55d4f99ec (HEAD -> 10.x) Author: itnetwork <[email protected]> Date: Thu Dec 21 14:30:51 2023 +0100 Vytvořena složka tasks diff --git a/tasks/soubor.txt b/tasks/soubor.txt new file mode 100644 index 00000000..2d750b67 --- /dev/null +++ b/tasks/soubor.txt @@ -0,0 +1 @@ +Testovaci soubor ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $
Hash jsme získali. Spusťme s ním tedy příkaz
git cat-file 9d75672de3f87202b615435d3a5ebbe55d4f99ec -p
, abychom
získali výpis obsahu commitu:
MINGW64:/c/mujgit/laravel ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git cat-file 9d75672de3f87202b615435d3a5ebbe55d4f99ec -p tree f53345c1ed5beaf290ee8edf4881c5a09f14226b parent ec4c318d68c305e42f32f2832cc8507b371f237f author itnetwork <[email protected]> 1703165451 +0100 committer itnetwork <[email protected]> 1703165451 +0100 Vytvořena složka tasks ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $
Obdrželi jsme výpis obsahu commitu. Vidíme, že tento commit obsahuje
nadřazený rodičovský objekt parent
, kterým je předešlý
commit.
Kromě prvního commitu každý commit v Gitu obsahuje odkaz
parent
na předešlý commit.
Abychom se podívali do objektu tree
, spusťme příkaz
git cat-file <hash commitu> -p
s hashem předchozího
commitu:
MINGW64:/c/mujgit/laravel ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git cat-file f53345c1ed5beaf290ee8edf4881c5a09f14226b -p 100644 blob 8f0de65c560259bd171d746d12aa187f666893a3 .editorconfig 100644 blob ea0665b0a60cfaafaa7b2c80992a0e406700e1a2 .env.example ... 040000 tree 8229fefca7d57f5c87adeef4e35dffa79bb691a6 tasks 100644 blob 2d750b67d34524994ba425d168d5ed2576c11492 testovaci_soubor.txt 040000 tree 49a71909565d8572e9d915c039b0fab49d0f4a1a tests 100644 blob 421b5695627db43c022947cfc7c0ecce6b9689be vite.config.js ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $
Získali jsme výpis obsahu objektu. Jak můžeme vidět,
strom obsahuje soubor testovaci_soubor.txt
s hashem
2d750b67d34524994ba425d168d5ed2576c11492
z předešlého commitu.
Nově obsahuje objekt tree
s hashem
8229fefca7d57f5c87adeef4e35dffa79bb691a6
.
Zobrazme si obsah tohoto stromu, tedy hash složky tasks/
,
tímto příkazem:
MINGW64:/c/mujgit/laravel ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git cat-file 8229fefca7d57f5c87adeef4e35dffa79bb691a6 -p 100644 blob 2d750b67d34524994ba425d168d5ed2576c11492 soubor.txt ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $
Spusťme příkaz git cat-file <hash commitu> -p
pro
zobrazení obsahu souboru testovaci_soubor.txt
s jeho hashem
2d750b67d34524994ba425d168d5ed2576c11492
(viz výše):
MINGW64:/c/mujgit/laravel ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ git cat-file 2d750b67d34524994ba425d168d5ed2576c11492 -p Testovaci soubor ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $
Příkaz nám vypsal jeho obsah, tedy Testovaci soubor
.
Závěr
Teď vidíme, že hash souboru soubor.txt
je stejný jako hash
souboru testovaci_soubor.txt
, přestože oba jsou různé soubory
na jiných místech. Git totiž rozpoznal, že oba soubory mají přesně týž
obsah. A proto se rozhodl vytvořit pouze jeden
blob
a použít stejnou referenci dvakrát, místo
aby vytvořil dva identické objekty.
Příkaz hash-object
Pojďme si ještě náš závěr potvrdit nízkoúrovňovým příkazem
hash-object
na stejném obsahu Testovaci soubor
obou
výše uvedených souborů. Příkaz vezme část obsahu a vrátí pro něj hash
klíč.
Spusťme následující příkaz hash-object
pro vytvoření
hashe řetězce Testovaci soubor
:
MINGW64:/c/mujgit/laravel ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $ echo "Testovaci soubor" | git hash-object --stdin 2d750b67d34524994ba425d168d5ed2576c11492 ItNetwork@DESKTOP-ADEVTG4 MINGW64 /c/mujgit/laravel (10.x) $
Pokud se nám zobrazí chyba, použijme příkaz
printf "Testovaci soubor" | git hash-object --stdin
.
Získali jsme hash 2d750b67d34524994ba425d168d5ed2576c11492
pro
řetězec Testovaci soubor
. To znamená, že pokud vytvoříme
další soubor .txt
s obsahem Testovaci soubor
, nový
commit bude odkazovat na stejný blob
se
stejným hashem.
Git zpracovává objekty vytvořené v databázi tak efektivně, že znovu
používá objekty blob
pokaždé, když je obsah stejný.
Nezáleží na tom, zda se jedná o jiný soubor vytvořený v jiné složce. To
je důvod, proč jsou názvy souborů uloženy ve
stromech. Toto rozhodnutí umožňuje systému Git zpracovávat
odkazy na stejný objekt blob
s různými
názvy souborů.
V příští lekci, Git - Grafické uživatelské rozhraní Git GUI, si představíme grafické uživatelské rozhraní Git GUI. Ukážeme si, jak v něm vytvořit commit a spravovat větve.