Mundarija (34)
- Bu darsda
- 1. Nega bu kerak?
- 2. Birinchi obyekt
- 2.1 Bo'sh repo
- 2.2 git cat-file — obyektni o'qish
- 3. SHA — mazmundan hisoblangan nom
- 3.1 Hash nima?
- 3.2 Qo'lda tekshirish
- 3.3 Bu nima beradi?
- 4. Tree — papka obyekti
- 5. Commit obyekti
- 5.1 «Bahor» commitining ichi
- 5.2 Tree'dan blob'gacha
- 6. Snapshot: farq emas, surat
- 6.1 Har commit — butun loyiha
- 6.2 DAG — commitlar grafi
- 7. Annotated tag obyekti
- 8. Packfile va git gc
- 8.1 Bo'sh obyektlar va to'plam
- 8.2 Snapshot va delta ziddiyatmi?
- 9. SHA-1 va SHA-256'ga o'tish
- 10. Ko'p uchraydigan xatolar
- 10.1 Mavjud bo'lmagan obyekt
- 10.2 .git/objects ni qo'lda o'zgartirish
- 10.3 "Git farqlarni saqlaydi"
- 10.4 HEAD^{tree} shell'da buzilishi
- 11. Mashqlar
- 1-mashq (oson): Obyekt turini toping
- 2-mashq (o'rta): Hashni qo'lda hisoblang
- 3-mashq (qiyin): Nechta yangi obyekt?
- 4-mashq: Portfolio qadami — o'z omboringizga qarang
- 12. Real ishda
- Xulosa
- Manbalar
Git ichkaridan: blob, tree, commit obyektlari va SHA
Qisqacha: Git har bir faylni, papkani va commitni obyekt sifatida
.git/objectsga yozadi. Obyekt nomi — uning mazmunidan hisoblangan SHA hash: bir xil mazmun doim bir xil nom oladi. To'rt tur bor: blob (fayl mazmuni), tree (papka), commit (surat + muallif + ota) va annotated tag. Commit farqlarni emas, butun loyihaning suratini (snapshot) ko'rsatadi. O'zgarmagan fayllar esa qayta saqlanmaydi.
Bu darsda
.git/objectsichida nima borliginigit cat-filebilan o'qiysiz.- Blob, tree, commit va annotated tag obyektlarini farqlaysiz.
- SHA hash qanday hisoblanishini qo'lda tekshirasiz va nega Git "mazmun bo'yicha manzillanadigan" ombor ekanini tushuntirasiz.
- Snapshot tushunchasini va packfile,
git gcishini bilasiz. - Git'dagi SHA-1 holatini va SHA-256'ga o'tish rejasini bilasiz.
Oldin bilishingiz kerak: Birinchi repo: init, status, add, commit, Xatoni tuzatish 2: reset va revert.
1. Nega bu kerak?
Oldingi darslarda Git'dan bir necha "sirli" narsalar chiqdi:
- Har commitning
dab5bffkabi nomi bor. U qayerdan keladi? create mode 100644— bu raqam nima (Birinchi repo darsida "keyin ochamiz" degan edik)?- Oldingi darsda revert'dan keyin menyu faylining nomi
63aadda— xuddi bir necha commit oldingidek bo'lib qoldi. Nega?
Bularning hammasiga bitta javob bor. Uni bilgan odam Git'ni "sehrli quti" deb emas, oddiy va mantiqiy ombor deb ko'radi. Keyingi darslarda branch, merge va rebase'ni o'rganganda ham shu rasm yordam beradi: har bir buyruq shu obyektlar ustida ishlaydi.
Hayotiy o'xshatish — kutubxona arxivi. Har bir hujjat alohida jildda saqlanadi. Jild raqami hujjat mazmunidan hisoblanadi: mazmun bir xil bo'lsa, raqam ham bir xil. Shuning uchun bir hujjatning ikki nusxasi hech qachon ikki jildga tushmaydi. Jildlar ro'yxati — papka. Ro'yxat va sanasi yozilgan varaqa — commit.
Bu dars "chuqur" qavatdan. Hamma buyruqlarni yodlash shart emas. Maqsad — rasmni tushunish.
2. Birinchi obyekt
2.1 Bo'sh repo
Tajriba uchun alohida repo ochamiz. kurs/sinov-git/ — tashlab yuboriladigan tajribalar papkasi (Yaxshi commit darsida ochgan edik). Uning ichida yangi repo:
cd ~/kurs
mkdir -p sinov-git/obyektlar
cd sinov-git/obyektlar
git init
find .git/objects -type ffind (Fayl qidirish darsidan) hech narsa chiqarmadi — yangi repoda obyekt yo'q. Bitta fayl yaratamiz va Git'dan uning nomini so'raymiz:
echo 'salom' > salom.txt
git hash-object salom.txt4de65895076ffaf8572ae06909fa475a10567eeagit hash-object — "bu fayl Git'ga qo'shilsa, qanday nom oladi?" degan savolga javob. Hali hech narsa yozilmadi. Endi faylni qutiga solamiz:
git add salom.txt
find .git/objects -type f.git/objects/4d/e65895076ffaf8572ae06909fa475a10567eea(git add CRLF ogohlantirishini ham chiqardi — bu darsda uni chiqishlardan olib tashlaymiz.) .git/objects da birinchi fayl paydo bo'ldi. Nomiga qarang: 4d — papka, qolgan 38 belgi — fayl nomi. Birga — aynan hash-object aytgan nom. Git obyektlarni nomining birinchi ikki belgisi bo'yicha papkalarga taqsimlaydi — bitta papkada yuz minglab fayl to'planmasin.
Demak, git add faylni qutiga solganda uning mazmunini allaqachon omborga yozadi. Commit keyin faqat "shu mazmunlar ro'yxati"ni muhrlaydi.
2.2 git cat-file — obyektni o'qish
Obyekt faylini cat bilan ochsangiz, tushunarsiz belgilar ko'rasiz: Git uni siqib saqlaydi (zlib — ZIP'ga o'xshash keng tarqalgan siqish usuli). O'qish uchun maxsus buyruq bor — git cat-file. Qisqa nom (kamida 4 belgi) ham yetadi:
git cat-file -t 4de6589
git cat-file -p 4de6589
git cat-file -s 4de6589blob
salom
6Uchta flag:
| Flag | Nimani ko'rsatadi |
|---|---|
-t |
Turi (type) |
-p |
Mazmuni, o'qiladigan ko'rinishda (pretty-print) |
-s |
Hajmi, baytda (size) |
Hajm 6: salom — 5 harf, oxiridagi yangi qator belgisi (LF) — yana bitta.
Blob (blob) — fayl mazmunini saqlaydigan obyekt. E'tibor bering: blobda fayl nomi yo'q. Faqat mazmun. Nom boshqa joyda — tree'da saqlanadi.
3. SHA — mazmundan hisoblangan nom
3.1 Hash nima?
Hash (xesh) — istalgan uzunlikdagi ma'lumotdan qat'iy uzunlikdagi "barmoq izi" hisoblaydigan funksiya natijasi. Bir xil ma'lumot — doim bir xil hash. Bitta harf o'zgarsa — butunlay boshqa hash.
Git bu ish uchun SHA-1 algoritmidan foydalanadi. Natija — 160 bit, ya'ni 40 ta o'n oltilik belgi (0–9 va a–f). Bu belgilar sizga CSS ranglaridan tanish: #2f6b4f ham o'n oltilik son. Shuning uchun commit nomlari 40 belgili. git log --oneline esa faqat boshidagi 7 tasini ko'rsatadi.
Bitta harfni katta qilamiz:
echo 'Salom' | git hash-object --stdin68fb6b9f8441e6b49ecd11a1708a82e0fa48cfe84de6589... bilan umumiy hech narsasi yo'q. --stdin — "faylni emas, pipe orqali kelgan matnni hisobla" (Oqimlar va yo'naltirish).
3.2 Qo'lda tekshirish
Git sir saqlamaydi — hashni o'zimiz hisoblab ko'ramiz. Git mazmun oldiga sarlavha qo'shadi: tur, bo'sh joy, hajm va nol bayt (\0). Keyin hammasidan SHA-1 hisoblaydi. Git Bash'dagi sha1sum dasturi bilan:
printf 'blob 6\0salom\n' | sha1sum4de65895076ffaf8572ae06909fa475a10567eea *-Aynan o'sha nom! Oxiridagi *- — sha1sum ning belgisi: "pipe'dan o'qildi". printf — echo ning aniqroq varianti, \0 va \n ni haqiqiy baytlarga aylantiradi.
Bu tajriba Git'ning butun g'oyasini ko'rsatadi: nom mazmundan kelib chiqadi. Buni mazmun bo'yicha manzillanadigan ombor (content-addressable storage) deyishadi. Obyektni topish uchun uning mazmunidan hisoblangan kalit ishlatiladi.
3.3 Bu nima beradi?
Uchta foyda:
- Takrorlanish yo'q. Bir xil mazmun — bitta obyekt, nechta faylda bo'lmasin.
- Buzilishni sezish. Diskdagi obyektning bitta bayti buzilsa, uning hashi nomiga mos kelmay qoladi. Git buni sezadi.
- Tarixni sezdirmay o'zgartirib bo'lmaydi. Commit hashi uning mazmunidan, mazmunida esa ota commitning hashi bor. Bittasini o'zgartirsangiz, undan keyingi hamma commitlarning nomi o'zgaradi. Versiya nazorati darsidagi "tarix himoyalangan" gapi shu.
Birinchisini ko'ramiz. Xuddi shu mazmunli ikkinchi fayl:
cp salom.txt nusxa.txt
git add nusxa.txt
find .git/objects -type f.git/objects/4d/e65895076ffaf8572ae06909fa475a10567eeaYangi obyekt paydo bo'lmadi! nusxa.txt ning mazmuni salom.txt niki bilan bir xil — Git uni allaqachon saqlagan.
Tekshirib ko'ring: Ali va Malika bir-birini bilmagan holda, ikki xil kompyuterda
salomso'zi yozilgan faylni Git'ga qo'shdi. Ularning blob nomlari bir xil bo'ladimi?
Javob
Ha, 4de6589... — ikkalasida ham. Blob nomi faqat mazmundan (va sarlavhadagi tur va hajmdan) hisoblanadi. Fayl nomi, kompyuter, vaqt va muallif blobga kirmaydi. Commitlarining nomi esa boshqa bo'ladi — commitda muallif va vaqt bor.
4. Tree — papka obyekti
Commit qilamiz va omborga yana qaraymiz:
git commit -m "Sinov: ikki bir xil fayl qo'sh"
find .git/objects -type f.git/objects/3e/9399e40428688660f81b445f51d18104b34646
.git/objects/4d/e65895076ffaf8572ae06909fa475a10567eea
.git/objects/6a/bfac771e1d970c8e39b4222565d55ff67dddbdIkki yangi obyekt: bittasi commit, bittasi — tree. HEAD^{tree} — "HEAD commitining tree'si" degani:
git cat-file -p 'HEAD^{tree}'100644 blob 4de65895076ffaf8572ae06909fa475a10567eea nusxa.txt
100644 blob 4de65895076ffaf8572ae06909fa475a10567eea salom.txtTree (tree) — papka obyekti: ichidagi har bir element uchun bitta qator. Qatorda to'rt narsa bor: rejim, tur, hash va nom. Endi nom paydo bo'ldi! Ikki nom bitta blobga ishora qiladi.
Rejim raqamlari — Birinchi repo darsidagi create mode 100644 ning javobi:
| Rejim | Ma'nosi |
|---|---|
100644 |
Oddiy fayl |
100755 |
Ishga tushiriladigan fayl (skript) |
040000 |
Papka (ichki tree) |
120000 |
Symlink (Qator oxiri va symlink) |
'HEAD^{tree}' ni qo'shtirnoqqa oldik: ba'zi shell'lar { } belgilarini o'zicha talqin qiladi.
5. Commit obyekti
5.1 «Bahor» commitining ichi
Endi haqiqiy loyihaga o'tamiz. «Bahor» reposida:
cd ~/kurs/bahor
git cat-file -t HEAD
git cat-file -p HEADcommit
tree d9cddcf9de0bae3aef2ff681544ad9dd61a94545
parent bd98d1bb2aeffb83a40f6745994ca8670af0a34d
author Aziz Karimov <aziz@example.com> 1790917920 +0500
committer Aziz Karimov <aziz@example.com> 1790917920 +0500
Menyu: lag'mon narxini qo'shMisollarni biz Birinchi repo darsi oxiridagi «Bahor»da ko'rsatamiz — HEAD bu yerda 07b061d. Sizda keyingi darslardagi commitlar ham bor, shuning uchun hashlar boshqa bo'ladi. Tuzilma esa aynan shu. Commit (commit) obyektida:
tree— loyiha ildiz papkasining tree'si. Butun surat shu bitta hash orqali.parent— ota commit. Oldingi darsda merge commitda ikkitaparentqatorini ko'rgan edik.author— kim yozgan,committer— kim commit qilgan. Odatda bir odam. Keyinroq, masalan boshqaning o'zgarishini ko'chirganda, farq qiladi.1790917920 +0500— vaqt: 1970-yil 1-yanvardan beri o'tgan soniyalar va Toshkent vaqt mintaqasi.git loguni odam tiliga o'giradi.- Bo'sh qatordan keyin — xabar.
Birinchi commitda parent qatori yo'q — Birinchi repo darsidagi (root-commit) aynan shu:
git cat-file -p dab5bfftree 882dc103895a022ed2a3fc590d58ba8b75e354d7
author Aziz Karimov <aziz@example.com> 1790830800 +0500
committer Aziz Karimov <aziz@example.com> 1790830800 +0500
Bahor: sayt tuzilmasini yarat5.2 Tree'dan blob'gacha
Commitning tree'sini ochamiz:
git cat-file -p d9cddcf040000 tree 0e65318d4cd157e38120ba67e99e85ec791d317d aloqa
040000 tree 7259bb6ed354ea899eb9ffac55fbecd138bf3010 assets
040000 tree b05140fea49b423debd476078f408a9510c22c34 bron
100644 blob 42c0d4ea734d13d27a8c329b349d90177720f38e index.html
040000 tree b2030974140093bfd7ebdc0c88166441b2dd681d menyuPapkalar — tree, fayl — blob. Chuqurroq tushish uchun HEAD:yo'l yozuvi qulay:
git cat-file -p HEAD:menyu
git cat-file -p HEAD:menyu/index.html100644 blob 8eecc123b58fcf432c4cc5deddaa0e4403d712c6 index.html
<h1>Menyu</h1>
<p>Osh — 35 000 so'm</p>
<p>Lag'mon — 28 000 so'm</p>Commit → tree → tree → blob. Versiya nazorati darsidagi git show dab5bff:menyu/index.html buyrug'i aynan shu yo'lni bosib o'tadi.
flowchart TD
C["commit 07b061d<br/>Menyu: lag'mon"] --> T["tree d9cddcf<br/>(ildiz)"]
C -. parent .-> P["commit bd98d1b"]
T --> A["tree: aloqa"]
T --> B["tree: bron"]
T --> M["tree: menyu"]
T --> I["blob: index.html"]
M --> MI["blob 8eecc12<br/>menyu/index.html"]
P --> T2["tree 3b1be60"]
T2 --> BNimaga qarang: pastdagi bd98d1b commitining tree'si ham xuddi o'sha bron tree'siga ishora qiladi. Ikki commit bitta papkani bo'lishib turibdi — keyingi bo'limda buni tekshiramiz.
git ls-tree -r HEAD butun daraxtni bitta ro'yxatda beradi:
100644 blob c1bd40cb28a904afa0bab24c72aa9a4c66c60dc7 aloqa/index.html
100644 blob 693ce9b84057d37872139150e32284abbbe76754 assets/css/asosiy.css
100644 blob 5dc70960c8f0a146925427d63e7fa512647d5f5e bron/index.html
100644 blob 6b69d3ab9821267c2683122f1df88f5b662de3d1 bron/rahmat.html
100644 blob 42c0d4ea734d13d27a8c329b349d90177720f38e index.html
100644 blob 8eecc123b58fcf432c4cc5deddaa0e4403d712c6 menyu/index.htmlTekshirib ko'ring: Blobda fayl nomi yo'q. Unda Git
menyu/index.htmldegan nomni qayerdan biladi?
Javob
Tree'lardan. Ildiz tree'da menyu nomi va uning tree hashi yozilgan, menyu tree'sida esa index.html nomi va blob hashi. Yo'l — tree'lar zanjiri bo'ylab yig'ilgan nomlar.
6. Snapshot: farq emas, surat
6.1 Har commit — butun loyiha
Ko'p versiya nazorati tizimlari har versiyada faqat farqni saqlaydi: "3-qatorga shu qo'shildi". Git boshqacha fikrlaydi. Har bir commit — butun loyihaning to'liq surati (snapshot): ildiz tree orqali har bir faylga yo'l bor. Eski commitni ochish uchun Git farqlarni birma-bir qo'shib chiqmaydi — shunchaki o'sha tree'ni o'qiydi.
"Har commitda butun loyiha? Disk to'lib ketmaydimi?" degan savol tug'iladi. Javob — hash. O'zgarmagan fayl va papka bir xil hashga ega, demak qayta saqlanmaydi. Tekshiramiz. Oxirgi commit faqat menyuni o'zgartirgan edi:
git rev-parse HEAD:bron HEAD~1:bron
git rev-parse HEAD:menyu HEAD~1:menyub05140fea49b423debd476078f408a9510c22c34
b05140fea49b423debd476078f408a9510c22c34
b2030974140093bfd7ebdc0c88166441b2dd681d
71209f281b31e9b29178ac7a5eb815c3afb69516git rev-parse — nomni to'liq hashga aylantiradigan buyruq (uni keyingi darsda yaqindan ko'ramiz). bron — ikki commitda bitta tree. menyu — ikki xil, chunki ichidagi fayl o'zgargan. aloqa papkasi esa uch commit davomida bir xil:
git rev-parse HEAD:aloqa HEAD~1:aloqa HEAD~2:aloqa0e65318d4cd157e38120ba67e99e85ec791d317d
0e65318d4cd157e38120ba67e99e85ec791d317d
0e65318d4cd157e38120ba67e99e85ec791d317dBitta fayl o'zgarsa, Git uchta yangi obyekt yozadi: yangi blob, uning papkasi uchun yangi tree va ildiz uchun yangi tree. Qolgan hamma narsa oldingi commit bilan bo'lishiladi.
Endi oldingi darsdagi savolga javob. Revert menyuni osh o'zgarishidan oldingi mazmunga qaytardi. Mazmun bir xil — demak blob nomi ham bir xil: 63aadda. Git yangi blob yozmadi, eskisini qayta ishlatdi.
6.2 DAG — commitlar grafi
Har commit o'z otasiga ishora qiladi. Ota — o'z otasiga. Bu zanjir faqat orqaga yo'nalgan va hech qachon aylana yasamaydi: commit o'zidan keyin yaratilgan commitga ishora qila olmaydi. Hashi hali ma'lum emas-ku.
Bunday tuzilma DAG (directed acyclic graph) — "yo'naltirilgan, aylanasiz graf" deyiladi. Graf — nuqtalar va ularni bog'lovchi chiziqlar. "Yo'naltirilgan" — chiziq bir tomonga qaraydi (bola → ota). "Aylanasiz" — chiziqlar bo'ylab yurib, boshlangan nuqtaga qaytib bo'lmaydi. Merge commitda ikki ota bo'lgani uchun tarix oddiy zanjir emas, aynan graf. Branch va merge darslaridagi hamma rasmlar — shu DAG.
7. Annotated tag obyekti
To'rtinchi obyekt turi — annotated tag. Tag (tag) — muhim commitga doimiy nom berish, masalan v1.0. Tag'larni Tag va relizlar darsida to'liq o'rganamiz. Hozir faqat ichini ko'ramiz:
git tag -a v1.0 -m "Bahor sayti: birinchi versiya"
git cat-file -t v1.0
git cat-file -p v1.0tag
object 07b061d79648257f6761433b3704325a26bbab77
type commit
tag v1.0
tagger Aziz Karimov <aziz@example.com> 1791608400 +0500
Bahor sayti: birinchi versiya-a (annotated) bilan yaratilgan tag — alohida obyekt: qaysi commitga ishora qilishi (object), kim va qachon qo'ygani (tagger) va xabari bor. -a siz yaratilgan "yengil" tag esa obyekt emas — shunchaki commitga yopishtirilgan nom:
git tag yengil
git cat-file -t yengilcommitGit to'rt tur obyekt biladi va boshqasi yo'q:
| Obyekt | Nima saqlaydi | O'xshatish |
|---|---|---|
| blob | Fayl mazmuni | Hujjat matni |
| tree | Nomlar va ichki obyektlar ro'yxati | Jild mundarijasi |
| commit | Tree, ota, muallif, vaqt, xabar | Sanali muhr |
| tag | Obyekt, tagger, xabar | Muhrga yopishtirilgan yorliq |
8. Packfile va git gc
8.1 Bo'sh obyektlar va to'plam
Hozircha har obyekt alohida faylda. Bunday obyekt loose object — "bo'sh (yig'ilmagan) obyekt" deyiladi. git count-objects -v ularni sanaydi:
git count-objects -vcount: 30
size: 2
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0
size-garbage: 0count: 30 — 30 ta bo'sh obyekt, size: 2 — ular diskda taxminan 2 KiB (kilobayt) joy oladi. Olti commitli kichik loyihada 30 obyekt. Katta loyihada yuz minglab bo'ladi. Yuz ming kichik fayl — disk uchun og'ir.
Shuning uchun Git vaqti-vaqti bilan obyektlarni bitta katta faylga yig'adi. Bu fayl packfile — "to'plam fayli" deyiladi. Qo'lda ishga tushiramiz:
git gc
git count-objects -v
ls .git/objects/packcount: 0
size: 0
in-pack: 30
packs: 1
size-pack: 4
prune-packable: 0
garbage: 0
size-garbage: 0
pack-08e86b80d6ba739be94669fbdd505efc16f87167.idx
pack-08e86b80d6ba739be94669fbdd505efc16f87167.pack
pack-08e86b80d6ba739be94669fbdd505efc16f87167.revcount: 0, in-pack: 30 — hamma obyekt endi bitta to'plamda. .pack — obyektlarning o'zi, .idx — tez topish uchun mundarija. .rev — yordamchi indeks. git gc (garbage collection) — "axlat yig'ish": obyektlarni to'playdi va hech qayerdan ishora qilinmaydigan eski obyektlarni vaqti kelganda o'chiradi.
git gc ni odatda qo'lda yozmaysiz. Git ko'p amallardan keyin o'zi tekshiradi va kerak bo'lsa ishga tushiradi. Obyektlarni o'qish esa o'zgarmaydi — git cat-file -p HEAD:menyu/index.html to'plam ichidan ham avvalgidek ishlaydi.
8.2 Snapshot va delta ziddiyatmi?
Bu yerda bitta nozik joy bor. Yuqorida "Git farqlarni emas, suratlarni saqlaydi" dedik. Lekin to'plam ichiga qarasak:
git verify-pack -v .git/objects/pack/pack-*.idxNatijadan bir necha qator (qolganini ... bilan qisqartirdik):
07b061d79648257f6761433b3704325a26bbab77 commit 239 173 12
...
3b1be60aa232bae33edf268db5b1b9911cc39058 tree 27 40 1569 1 d9cddcf9de0bae3aef2ff681544ad9dd61a94545
...
non delta: 26 objects
chain length = 1: 2 objects
chain length = 2: 1 object
chain length = 3: 1 object3b1be60 tree'si to'liq saqlanmagan: u d9cddcf ga nisbatan farq — delta sifatida yozilgan. Demak Git baribir farq saqlaydimi?
Ikkalasi ham rost, chunki ular ikki xil qavatda. Mantiqan har commit — to'liq surat: cat-file doim butun obyektni beradi, siz hech qachon delta ko'rmaysiz. Diskda esa, to'plam ichida, Git joy tejash uchun o'xshash obyektlarni bir-biriga nisbatan siqadi. Bu — faqat saqlash usuli. Xuddi rasmlar arxivini ZIP qilganday: arxiv ichida siqilgan, ochsangiz — asl rasm.
Tekshirib ko'ring:
git gcdan keyin.git/objects/4d/...kabi alohida fayllar yo'qoldi.git logvagit showishlashda davom etadimi?
Javob
Ha. Obyektlar o'chirilmadi, faqat bitta .pack fayliga ko'chirildi. Git obyektni avval alohida fayllardan, keyin to'plamlardan qidiradi. Buyruqlar uchun farqi yo'q.
9. SHA-1 va SHA-256'ga o'tish
SHA-1 1990-yillarda yaratilgan. Keyinchalik unga qarshi amaliy hujumlar topildi. 2017-yilda tadqiqotchilar bir xil SHA-1 hashli ikki xil PDF fayl yasashdi (SHAttered hujumi). Rasmiy Git hujjatlari bu haqda shunday deydi:
- Git ma'lum hujumlarga qarshi himoyaga ega. Lekin kelajakda yangi hujumlar topilishi kutiladi.
- Git allaqachon SHA-256 ni qo'llaydi — 64 belgili, xavfsizroq hash. Yangi repo yaratishda tanlash mumkin:
git init --object-format=sha256. - Hozircha SHA-256'li va SHA-1'li repolar o'zaro ishlamaydi: biridagi commitlarni ikkinchisiga yuborib bo'lmaydi.
- "BreakingChanges" hujjatiga ko'ra, kelajakdagi Git 3.0 da yangi repolar uchun standart hash SHA-256'ga almashadi. Uning chiqish sanasi hali belgilanmagan. SHA-1 formatidan voz kechish rejasi esa hozircha yo'q.
Sinab ko'ramiz — yana sinov-git/ ichida:
cd ~/kurs/sinov-git
git init --object-format=sha256 sha256
cd sha256
echo 'salom' > salom.txt
git hash-object salom.txt
git rev-parse --show-object-formatInitialized empty Git repository in C:/Users/.../kurs/sinov-git/sha256/.git/
caa79a099664a4e0d29775d82115ac834c67a0d3e311cb34bdf34d0997c20149
sha256O'sha salom — endi 64 belgili nom. «Bahor» reposida esa git rev-parse --show-object-format sha1 deydi.
Amalda nima qilish kerak? Hech narsa. Hozircha kursda va deyarli barcha real loyihalarda SHA-1 repolar ishlatiladi. Faqat bitta odatni oling: skriptlaringizda "hash doim 40 belgili" deb hisoblamang. Kelajakda u 64 bo'lishi mumkin.
Tajriba tugagach, bu papkani o'chirishingiz mumkin: cd ~/kurs/sinov-git qilib, keyin rm -rf sha256.
10. Ko'p uchraydigan xatolar
10.1 Mavjud bo'lmagan obyekt
git cat-file -p abc1234fatal: Not a valid object name abc1234Tarjimasi: "abc1234 — yaroqli obyekt nomi emas". Bunday hashli obyekt reposida yo'q — ehtimol hash boshqa repodan ko'chirilgan yoki bir harf xato yozilgan. Juda qisqa nom (masalan 12) ham xuddi shu xatoni beradi: Git kamida 4 belgi talab qiladi.
10.2 .git/objects ni qo'lda o'zgartirish
Obyekt fayllarini o'chirish, nomini o'zgartirish yoki tahrirlash — repo buzilishining eng tez yo'li. Hash nomga mos kelmay qoladi, commitlar yo'qolgan obyektlarga ishora qiladi. Faqat o'qing, va faqat git cat-file orqali.
10.3 "Git farqlarni saqlaydi"
Intervyuda keng tarqalgan noto'g'ri javob. To'g'ri javob: har commit — butun loyihaning surati. O'zgarmagan fayllar hash tufayli qayta saqlanmaydi. Diskdagi delta — faqat to'plam ichidagi siqish usuli.
10.4 HEAD^{tree} shell'da buzilishi
{ } belgilari ba'zi shell'larda (masalan PowerShell'da) maxsus ma'noga ega. Natija kutilmagan bo'lsa — qo'shtirnoqqa oling: 'HEAD^{tree}'.
11. Mashqlar
1-mashq (oson): Obyekt turini toping
«Bahor» reposida quyidagilarning har biri qaysi turdagi obyekt? Avval taxmin qiling, keyin git cat-file -t bilan tekshiring:
HEADHEAD:menyuHEAD:menyu/index.htmlHEAD^{tree}
Ishora: «Tree'dan blob'gacha» bo'limidagi diagramma.
Yechim
git cat-file -t HEAD
git cat-file -t HEAD:menyu
git cat-file -t HEAD:menyu/index.html
git cat-file -t 'HEAD^{tree}'commit
tree
blob
treeCommit — surat va muhr. Papka — tree. Fayl — blob. Commitning ildiz papkasi ham tree.
2-mashq (o'rta): Hashni qo'lda hisoblang
echo 'choy' | git hash-object --stdin qaysi hashni berishini sha1sum bilan tekshiring. Bo'sh joylarni to'ldiring: mazmun choy va yangi qator — jami bayt. Buyruq printf 'blob N\0choy\n' | sha1sum ko'rinishida bo'ladi, bu yerda N o'rniga o'sha son yoziladi.
Ishora: «Qo'lda tekshirish» bo'limi — salom 5 harf edi va hajmi 6 chiqdi.
Yechim
echo 'choy' | git hash-object --stdin
printf 'blob 5\0choy\n' | sha1sumIkkala buyruq bir xil 40 belgili hash chiqaradi (oxirida faqat sha1sum ning *- belgisi farq qiladi). choy — 4 harf, plyus yangi qator belgisi — 5 bayt. Hajmni noto'g'ri yozsangiz, hash butunlay boshqa chiqadi.
3-mashq (qiyin): Nechta yangi obyekt?
«Bahor»da faqat bron/rahmat.html ga bitta qator qo'shib, commit qilsangiz, .git/objects ga nechta yangi obyekt yoziladi? Qaysilar?
Ishora: «Har commit — butun loyiha» bo'limi — o'zgargan faylning yo'li bo'ylab yuqoriga chiqing.
Yechim
To'rtta:
rahmat.htmlning yangi mazmuni uchun blob.bronpapkasi uchun yangi tree — ichidagi bitta qator (rahmat.html hashi) o'zgardi.- Ildiz uchun yangi tree — undagi
bronqatorining hashi o'zgardi. - Yangi commit.
aloqa, menyu, assets tree'lari va bron/index.html blobi eski commit bilan bo'lishiladi. git count-objects -v ni commitdan oldin va keyin ishga tushirib tekshiring: count to'rtga oshadi (git gc dan keyin bo'lsa, 0 dan 4 ga).
4-mashq: Portfolio qadami — o'z omboringizga qarang
kurs/portfolioda birinchi commitingizning ichini oching:git cat-file -p HEAD. Qatorlardan qaysi biriparentemas,tree?- Ildiz tree'ni oching:
git cat-file -p 'HEAD^{tree}'. Qaysi fayllar bir xil blob hashga ega? Nega? git cat-file -p HEAD:sayt— qaysi ikki papka bir xil tree hashga ega?git count-objects -vni yozing, keyingit gcva yanagit count-objects -vH(-H— hajmni odam o'qiydigan ko'rinishda).- Savol:
asosiy-eski.cssni Yaxshi commit darsidagit rmbilan o'chirgan edingiz, lekin birinchi commitda u bor. Birinchi commit SHA'sinigit log --onelinening eng pastki qatoridan oling (bizda63190c1) va solishtiring:git rev-parse HEAD:sayt/assets/css/asosiy.css 63190c1:asosiy-eski.css. Nima chiqdi?
mashqlar repo: shu darsning 1–3-mashq javoblarini mashqlar/07/11-obyektlar/javoblar.md ga yozing va commit qiling: 07/11: obyektlar mashqlari javoblarini qo'sh.
Yechim
cd ~/kurs/portfolio
git cat-file -p HEAD
git cat-file -p 'HEAD^{tree}'
git cat-file -p HEAD:sayt
git count-objects -v
git gc
git count-objects -vH
git rev-parse HEAD:sayt/assets/css/asosiy.css 63190c1:asosiy-eski.cssBiz Birinchi repo darsidagi qisqa portfolio'da sinadik — unda fayllar bir qatorli va asosiy-eski.css hali o'chirilmagan. Ildiz tree'dan parcha:
100644 blob c2658d7d1b31848c3b71960543cb0368e56cd4c7 .gitignore
100644 blob 0967ef424bce6791893e9a57bb952f80fd536e93 .htmlvalidate.json
100644 blob c2658d7d1b31848c3b71960543cb0368e56cd4c7 .htmlvalidateignore
100644 blob 0967ef424bce6791893e9a57bb952f80fd536e93 .prettierrc
...Bizda .gitignore va .htmlvalidateignore bir xil (node_modules/), .prettierrc va boshqa ikki sozlama fayli ham bir xil ({}). sayt ichida aloqa va haqimda bir xil tree, chunki ichidagi index.html lar bir xil. Sizning haqiqiy fayllaringiz uzunroq va turli — ehtimol bunday moslik kamroq bo'ladi. Birinchi commitda parent qatori yo'q.
Oxirgi buyruq bizda ikki bir xil hash chiqardi: asosiy-eski.css va hozirgi CSS mazmuni bir xil edi — Git ularni bitta blob sifatida saqlagan. Sizda CSS o'shandan beri o'zgargan bo'lsa, ikki xil hash chiqadi. Qanday bo'lmasin, eski fayl o'chirilgan bo'lsa ham uning mazmuni birinchi commit orqali omborda turibdi.
12. Real ishda
- Commit hashi — dasturchilar tilidagi aniq manzil. Xato hisobotlarida, Pull Request izohlarida, deploy jurnallarida "
a1b2c3dcommitdan keyin buzildi" deb yoziladi. Hash hech qachon boshqa commitni ko'rsatmaydi. - Deploy tizimlari ko'pincha versiyani commit hashi bilan belgilaydi — qaysi kod ishlayotgani aniq bo'ladi. Masalan, Docker — dasturni server uchun "qutiga" qadoqlaydigan vosita (keyingi qismlarda o'rganamiz, hozir bilish shart emas).
- GitHub ham
.gitombori bilan ishlaydi. Siz yuborganda, faqat serverda yo'q obyektlar yuboriladi — tarixning qolgani allaqachon bor. Remote darsidaCounting objects,Compressing objectsqatorlarini ko'rganda, bu darsni eslaysiz. - Intervyu savollari: "Git farqlarni saqlaydimi yoki snapshotlarnimi?", "Blob, tree, commit nima?", "Nega commit hashini o'zgartirmasdan tarixni tahrirlab bo'lmaydi?" O'rta darajadagi (middle) dasturchi suhbatlarida tez-tez uchraydi.
Xulosa
- Git — mazmun bo'yicha manzillanadigan ombor: obyekt nomi — mazmunidan hisoblangan SHA hash.
- To'rt obyekt: blob (mazmun), tree (nomlar), commit (tree + ota + muallif + xabar), annotated tag.
- Har commit — to'liq surat; o'zgarmagan fayl va papkalar bir xil hash tufayli bo'lishiladi.
git cat-file -t/-p/-s— har qanday obyektni o'qish;.git/objectsni qo'lda o'zgartirmang.git gcobyektlarni packfile'ga yig'adi; delta — faqat disk ichidagi siqish.- Hozir SHA-1; Git 3.0 da yangi repolar uchun SHA-256'ga o'tish rejalashtirilgan.
Keyingi dars: HEAD, refs va detached HEAD — commitlarga qanday qilib main va HEAD kabi nomlar yopishtirilishini va bu nomlar qayerda saqlanishini ko'ramiz.
Manbalar
- Pro Git kitobi: "Git Internals — Git Objects", "Packfiles" — git-scm.com/book
- Git hujjati: "git-cat-file", "git-hash-object", "git-gc", "git-init" (
--object-format) — git-scm.com/docs - Git hujjati: "BreakingChanges" (Git 3.0 rejasi) — git-scm.com/docs/BreakingChanges
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!