Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. Ref — commitga yopishtirilgan nom
- 2.1 main fayli
- 2.2 HEAD fayli
- 3. Commit yorliqni suradi
- 4. git rev-parse — nomdan hashga
- 5. Detached HEAD
- 5.1 Eski commitga borish
- 5.2 Nima o'zgardi?
- 5.3 Detached holatda commit
- 5.4 Chiqish va ogohlantirish
- 5.5 Eski usul: git checkout
- 6. Maxsus HEAD'lar: ORIG_HEAD va FETCH_HEAD
- 6.1 ORIG_HEAD — xavfli amaldan oldingi joy
- 6.2 FETCH_HEAD — oxirgi olib kelingan narsa
- 7. packed-refs — ref'lar bitta faylda
- 8. Ko'p uchraydigan xatolar
- 8.1 Detached HEAD'dan qo'rqish
- 8.2 Ogohlantirishni o'qimasdan chiqish
- 8.3 switch ga hash berish
- 8.4 .git fayllarini qo'lda tahrirlash
- 8.5 Mavjud bo'lmagan nom
- 9. Mashqlar
- 1-mashq (oson): Kim kimga ishora qiladi?
- 2-mashq (o'rta): Vaqt sayohati
- 3-mashq (qiyin): Yo'qolgan sinov
- 4-mashq: Portfolio qadami — portfolio'ning birinchi versiyasi
- 10. Real ishda
- Xulosa
- Manbalar
Git HEAD va refs: branch, detached HEAD va ORIG_HEAD
Qisqacha: Branch — commit hashi yozilgan kichik fayl (
.git/refs/heads/main).HEAD— "hozir qayerdasiz" degan ko'rsatkich, odatda branch nomiga ishora qiladi:ref: refs/heads/main. Commit qilganda Git branch faylidagi hashni yangilaydi.HEADto'g'ridan-to'g'ri commitga ishora qilsa — bu detached HEAD: xavfli emas, faqat yangi commitlarni branch bilan saqlab qo'yish kerak.
Bu darsda
.git/HEADva.git/refsichidagi fayllarni o'qiysiz va commit ularni qanday o'zgartirishini ko'rasiz.- Symbolic ref nima ekanini va
git rev-parsebilan istalgan nomni hashga aylantirishni bilasiz. - Detached HEAD holatiga ataylab kirasiz, unda commit qilasiz va ishni yo'qotmasdan chiqasiz.
ORIG_HEADbilan reset'ni bekor qilasiz,FETCH_HEADvapacked-refsni taniysiz.
Oldin bilishingiz kerak: Git ichkaridan: obyektlar, SHA va snapshot, Xatoni tuzatish 2: reset va revert.
1. Nega bu kerak?
Oldingi darsda Git omborini ochdik: blob, tree, commit — hammasi hash nomli obyektlar. Lekin bir savol qoldi. 07b061d kabi hashlarni hech kim yodlamaydi. Biz esa har kuni main, HEAD, HEAD~1 deb yozamiz. Bu nomlar qayerda saqlanadi va qanday qilib to'g'ri commitni topadi?
Javobni bilmagan odam uchun bir holat ayniqsa qo'rqinchli. Bir kuni terminalda shu xabar chiqadi:
You are in 'detached HEAD' state."Ajralgan HEAD"! Nimadir buzildimi? Ko'pchilik shu yerda vahimaga tushadi. Aslida bu oddiy holat. Dars oxirida uni o'zingiz ataylab yaratasiz va xotirjam chiqasiz.
Hayotiy o'xshatish: kitobdagi xatcho'plar. Kitob — commitlar tarixi. Xatcho'p — branch: "shu betdaman" deb qo'yilgan yorliq. Xatcho'pni istalgan betga ko'chirish mumkin, kitob o'zgarmaydi. HEAD esa sizning barmog'ingiz: hozir qaysi xatcho'pni ushlab o'qiyapsiz. Ba'zan barmoq xatcho'psiz, to'g'ridan-to'g'ri betni ushlaydi. Bu — detached HEAD.
2. Ref — commitga yopishtirilgan nom
2.1 main fayli
«Bahor» reposida oxirgi commitlar:
git log --oneline -307b061d (HEAD -> main) Menyu: lag'mon narxini qo'sh
bd98d1b Bron: rahmat sahifasini qo'sh
b09fa2a Aloqa: sahifa yarat(Misollarni Birinchi repo darsi oxiridagi «Bahor»da ko'rsatamiz. Sizda keyingi darslardagi commitlar ham bor — hashlar boshqacha bo'ladi.)
Qavs ichidagi (HEAD -> main) ni oldingi darslarda ko'rgansiz. Bugun uning ma'nosini ochamiz. Avval main qayerda ekanini topamiz:
cat .git/refs/heads/main07b061d79648257f6761433b3704325a26bbab77Hammasi shu! main branch'i — bitta qatorli matn fayli, ichida commitning 40 belgili hashi. Boshqa hech narsa yo'q.
Ref (reference, havola) — commit (yoki boshqa obyekt) hashini saqlaydigan nomli ko'rsatkich. Branch — ref'ning bir turi. Barcha ref'lar .git/refs papkasida turadi:
ls .git/refs .git/refs/heads.git/refs:
heads
tags
.git/refs/heads:
mainheads — branch'lar (Git'da branch'ning ichki nomi "head" — "uch", tarmoq uchi). tags — tag'lar. Hozircha bitta branch — main.
2.2 HEAD fayli
cat .git/HEADref: refs/heads/mainHEAD faylida hash emas, boshqa ref'ning nomi yozilgan: "men refs/heads/main ga ishora qilaman". Boshqa ref'ga ishora qiladigan ref symbolic ref (ramziy havola) deyiladi. Uni maxsus buyruq bilan ham o'qish mumkin:
git symbolic-ref HEADrefs/heads/mainEndi (HEAD -> main) ning ma'nosi aniq: "HEAD main ga ishora qiladi, main esa shu commitga". Zanjir ikki qadamli:
flowchart LR
H["HEAD<br/>ref: refs/heads/main"] --> M["main<br/>07b061d…"]
M --> C["commit 07b061d<br/>Menyu: lag'mon"]
C --> P["commit bd98d1b"]Nimaga qarang: HEAD commitni to'g'ridan-to'g'ri bilmaydi — u faqat branch nomini biladi. Commitni branch biladi.
Tekshirib ko'ring:
.git/refs/heads/mainfaylini o'chirsangiz (buni qilmang!),07b061dcommiti yo'qoladimi?
Javob
Yo'q. Commit — .git/objects dagi obyekt, ref esa unga yopishtirilgan nom. Nom yo'qolsa, commit omborda qoladi, faqat unga "yetib boradigan" yo'l yo'qoladi. Xuddi xatcho'p tushib qolsa ham, kitob betlari joyida qolgani kabi. Topib olish usullarini Reflog darsida o'rganamiz.
3. Commit yorliqni suradi
Aziz bosh sahifaga ish vaqtini qo'shdi va commit qildi:
echo '<p>Ish vaqti: 08:00–23:00</p>' >> index.html
git add index.html
git commit -m "Bosh sahifa: ish vaqtini qo'sh"[main a0e2a64] Bosh sahifa: ish vaqtini qo'sh
1 file changed, 1 insertion(+)(git add CRLF ogohlantirishini chiqardi — bu darsda uni tashlab ketamiz.) Ikkala faylga yana qaraymiz:
cat .git/refs/heads/main
cat .git/HEADa0e2a6459d40b45c7e214df2ee02a359f41d1806
ref: refs/heads/mainmain fayli yangi hashni oldi. HEAD esa o'zgarmadi — u hamon main ga ishora qiladi. Commit paytida Git uch ish qiladi:
- Yangi commit obyektini yozadi. Uning
parenti —HEADorqali topilgan eski commit (07b061d). HEADqaysi branch'ga ishora qilayotganini aniqlaydi —main.mainfaylidagi hashni yangi commitga almashtiradi.
Branch shuning uchun "o'sadi": har commitda yorliq bir qadam oldinga siljiydi. Reset darsida esa reset aynan shu faylni orqaga — eski hashga — yozgan edi. --soft, --mixed, --hard farqi — faqat qutiga va stolga nima bo'lishida.
4. git rev-parse — nomdan hashga
Faylni cat bilan o'qish ta'lim uchun yaxshi, lekin ishda Git'ning o'z buyrug'i ishlatiladi. git rev-parse istalgan nomni to'liq hashga aylantiradi:
git rev-parse HEAD
git rev-parse --short HEAD
git rev-parse main
git rev-parse HEAD~2a0e2a6459d40b45c7e214df2ee02a359f41d1806
a0e2a64
a0e2a6459d40b45c7e214df2ee02a359f41d1806
bd98d1bb2aeffb83a40f6745994ca8670af0a34dGit nomni qanday tushunadi? U bir necha joyni tartib bilan tekshiradi: .git dagi maxsus nomlar (HEAD kabi), keyin refs/tags/, refs/heads/ va boshqa papkalar. HEAD~2 kabi yozuvda avval HEAD ni topadi, keyin ota zanjiri bo'ylab ikki qadam yuradi (Tarixni o'qish).
Yana bir necha foydali shakl:
| Buyruq | Nima beradi |
|---|---|
git rev-parse --abbrev-ref HEAD |
Hozirgi branch nomi (main) |
git rev-parse @ |
@ — HEAD ning qisqa yozuvi |
git rev-parse --show-toplevel |
Repo ildiz papkasi (Birinchi repo) |
git rev-parse --verify nom |
Nom mavjudligini tekshirish |
Mavjud bo'lmagan nom bilan:
git rev-parse --verify yoq-branchfatal: Needed a single revisionTarjimasi: "Bitta aniq revision (commit) kerak edi". Ya'ni yoq-branch nomidan hech qanday commit topilmadi. Skriptlarda bu xato "bunday branch yo'q" degan javob sifatida ishlatiladi.
Barcha ref'larni bir ro'yxatda git show-ref beradi:
git tag -a v1.0 -m "Bahor sayti: birinchi versiya"
git show-refa0e2a6459d40b45c7e214df2ee02a359f41d1806 refs/heads/main
466a40f8f7939738aa26248689270b4388406a1f refs/tags/v1.0Tag ham ref — refs/tags/v1.0 fayli. Uning hashi commitniki emas, chunki annotated tag o'zi alohida obyekt (oldingi darsda ko'rgan edik). Tag'larni Tag va relizlar darsida o'rganamiz.
Tekshirib ko'ring: Yangi commitdan keyin
.git/HEADfayli o'zgaradimi?.git/refs/heads/main-chi?
Javob
.git/HEAD o'zgarmaydi — unda ref: refs/heads/main yozuvi qoladi. .git/refs/heads/main o'zgaradi — unga yangi commitning hashi yoziladi. HEAD branch'ni ko'rsatadi, branch esa commitni.
5. Detached HEAD
5.1 Eski commitga borish
Jasur aka so'radi: "Menyu birinchi narx qo'shilgan kuni qanday ko'rinardi?" Versiya nazorati darsida bitta faylni git show dab5bff:menyu/index.html bilan ko'rgan edik. Lekin butun saytni brauzerda ochib ko'rmoqchi bo'lsak, fayllarning o'zi o'sha holatga qaytishi kerak.
Restore darsida git switch bilan tanishgansiz. Unga commit hashini beramiz:
git switch f4238e7fatal: a branch is expected, got commit 'f4238e7'
hint: If you want to detach HEAD at the commit, try again with the --detach option.Tarjimasi: "Branch kutilgan edi, commit berildi. Maslahat: agar HEAD'ni shu commitda ajratmoqchi bo'lsangiz, --detach bilan qayta urining". switch ehtiyotkor: u ataylab so'raydi. Maslahatga amal qilamiz:
git switch --detach f4238e7HEAD is now at f4238e7 Menyu: osh narxini qo'sh5.2 Nima o'zgardi?
cat .git/HEADf4238e7b653db61eee50abc338446f66b8a7634dHEAD faylida endi ref: ... emas, to'g'ridan-to'g'ri commit hashi. HEAD branch'dan "ajraldi" — shuning uchun detached HEAD (ajralgan HEAD) deyiladi.
flowchart LR
H["HEAD<br/>f4238e7…"] --> C1["commit f4238e7<br/>osh narxi"]
M["main<br/>a0e2a64…"] --> C3["commit a0e2a64<br/>ish vaqti"]
C3 --> C2["… 07b061d …"]
C2 --> C1Nimaga qarang: main joyida — u hamon eng yangi commitni ko'rsatadi. Faqat HEAD eski commitga ko'chdi. Hech narsa o'chmadi.
Git holatni aniq aytadi:
git status
cat menyu/index.htmlHEAD detached at f4238e7
nothing to commit, working tree clean
<h1>Menyu</h1>
<p>Osh — 35 000 so'm</p>Menyuda lag'mon yo'q — fayllar o'sha kundagi holatda. Endi index.html ni brauzerda ochsangiz, saytning o'sha kungi ko'rinishini ko'rasiz. git log --oneline esa faqat f4238e7 va undan oldingisini ko'rsatadi: HEAD dan orqaga yuradi. Yangi commitlarni ko'rish uchun --all kerak:
git log --oneline --all -3a0e2a64 (tag: v1.0, main) Bosh sahifa: ish vaqtini qo'sh
07b061d Menyu: lag'mon narxini qo'sh
bd98d1b Bron: rahmat sahifasini qo'shE'tibor bering: main yonida endi HEAD -> yo'q — HEAD boshqa joyda.
5.3 Detached holatda commit
Detached HEAD'da commit qilish mumkin. Aziz sinov uchun eski menyuga choy narxini qo'shdi:
echo "<p>Choy — 3 000 so'm</p>" >> menyu/index.html
git commit -a -m "Menyu: choy narxini qo'sh (sinov)"
git log --oneline -3[detached HEAD c1ecb39] Menyu: choy narxini qo'sh (sinov)
1 file changed, 1 insertion(+)
c1ecb39 (HEAD) Menyu: choy narxini qo'sh (sinov)
f4238e7 Menyu: osh narxini qo'sh
dab5bff Bahor: sayt tuzilmasini yaratCommit natijasida branch nomi o'rnida detached HEAD yozildi. Git yangi commit yaratdi va HEAD faylini yangiladi — boshqa hech qanday ref'ni emas. Bu commitni faqat HEAD "biladi".
5.4 Chiqish va ogohlantirish
main ga qaytamiz:
git switch mainWarning: you are leaving 1 commit behind, not connected to
any of your branches:
c1ecb39 Menyu: choy narxini qo'sh (sinov)
If you want to keep it by creating a new branch, this may be a good time
to do so with:
git branch <new-branch-name> c1ecb39
Switched to branch 'main'Tarjimasi: "Ogohlantirish: siz birorta branch'ingizga ulanmagan 1 ta commitni ortda qoldiryapsiz: c1ecb39. Uni saqlamoqchi bo'lsangiz, hozir yangi branch yaratish ayni vaqti: git branch <yangi-branch-nomi> c1ecb39. main branch'iga o'tildi".
Git ogohlantirdi, lekin to'xtatmadi. Endi HEAD yana main da, c1ecb39 ga esa hech qaysi ref ishora qilmaydi. git log uni ko'rsatmaydi. Commit omborda bir muddat qoladi, lekin nomsiz.
Git'ning o'zi aytgan yo'l bilan qutqaramiz. git branch nom hash — shu commitga yangi branch (yorliq) yopishtiradi. Branch'lar bilan to'liq ishlashni Branch nima darsida o'rganamiz. Hozir faqat bitta buyruq:
git branch chore/eski-menyu-sinov c1ecb39
git branch chore/eski-menyu-sinov
* mainSinov commiti endi nomli — chore/eski-menyu-sinov. U yo'qolmaydi. Nomdagi chore/ — "xizmat ishi" prefiksi; branch nomlash qoidalarini Branch nima darsida ko'ramiz. * — HEAD qaysi branch'da ekanini ko'rsatadi.
Maslahat: Detached HEAD'da commit qilmoqchi bo'lsangiz, oldindan branch yarating:
git switch -c yangi-nom. Shunda chiqishda hech narsa "ortda" qolmaydi.-c(create) ni Branch nima darsida batafsil ko'rasiz.
5.5 Eski usul: git checkout
Eski maqolalarda va ko'p dasturchilarning odatida git checkout <hash> uchraydi. U ogohlantirishsiz, darhol detached holatga o'tadi — lekin uzun tushuntirish chiqaradi:
git checkout dab5bffNote: switching to 'dab5bff'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at dab5bff Bahor: sayt tuzilmasini yaratTarjimasi (asosiy qismi): "Siz 'detached HEAD' holatidasiz. Atrofga qarashingiz, tajriba uchun o'zgartirishlar kiritib, ularni commit qilishingiz mumkin. Branch'ga qaytsangiz, bu commitlarni hech qaysi branch'ga ta'sir qilmasdan tashlab ketishingiz mumkin. Yaratgan commitlaringizni saqlamoqchi bo'lsangiz, switch -c bilan yangi branch yarating".
Ya'ni Git'ning o'zi detached HEAD'ni xavfsiz "sayr qilish rejimi" deb tushuntiradi. Orqaga qaytish uchun git checkout - yoki git switch - — "oldingi joyga". Restore darsida aytilganidek, checkout juda ko'p ish qiladi, shuning uchun yangi kodda switch --detach aniqroq.
git checkout -Previous HEAD position was dab5bff Bahor: sayt tuzilmasini yarat
Switched to branch 'main'Tekshirib ko'ring: Detached HEAD'da ikki commit qildingiz va
git switch mainbilan chiqdingiz. Ogohlantirishni o'qimay o'tib ketdingiz. Commitlar o'chib ketdimi?
Javob
Darhol o'chmaydi — ular omborda qoladi, faqat hech qanday branch ularni ko'rsatmaydi. Hashini bilsangiz (ogohlantirishda yozilgan edi), git branch nom hash bilan qutqarasiz. Hashni unutgan bo'lsangiz, uni Reflog topib beradi. Uzoq vaqt nomsiz qolgan commitlarni esa git gc oxir-oqibat o'chiradi.
6. Maxsus HEAD'lar: ORIG_HEAD va FETCH_HEAD
.git ichida HEAD dan boshqa "…_HEAD" fayllar ham paydo bo'ladi. Ikkitasi eng ko'p uchraydi.
6.1 ORIG_HEAD — xavfli amaldan oldingi joy
reset, merge va rebase kabi HEAD ni katta masofaga suradigan buyruqlar eski joyni ORIG_HEAD ga yozib qo'yadi. Sinab ko'ramiz. Aziz sinov commit qildi va uni reset --hard bilan tashladi:
echo 'body { background: red; }' >> assets/css/asosiy.css
git commit -a -m "Sinov: fonni qizil qil"
git reset --hard HEAD~1
cat .git/ORIG_HEAD
git log --oneline -1 ORIG_HEAD[main 1043d95] Sinov: fonni qizil qil
1 file changed, 1 insertion(+)
HEAD is now at a0e2a64 Bosh sahifa: ish vaqtini qo'sh
1043d95e62a17a299e9cf27f8b3fe690c0a09ab6
1043d95 Sinov: fonni qizil qilORIG_HEAD reset'dan oldingi commitni eslab qoldi. Aziz fikridan qaytdi: "Yo'q, u commit kerak edi". Bitta buyruq:
git reset --hard ORIG_HEAD
git log --oneline -2HEAD is now at 1043d95 Sinov: fonni qizil qil
1043d95 (HEAD -> main) Sinov: fonni qizil qil
a0e2a64 (tag: v1.0) Bosh sahifa: ish vaqtini qo'shReset bekor qilindi. Faqat bitta cheklov bor: ORIG_HEAD har yangi reset, merge yoki rebase'da qayta yoziladi — faqat oxirgi xavfli amalni eslaydi. Uzoqroq tarix uchun Reflog bor. Va eslang: commit qilinmagan ishni ORIG_HEAD ham qaytarmaydi (Reset darsidagi ogohlantirish).
(Sinovdan keyin biz yana git reset --hard HEAD~1 bilan qizil fonni olib tashladik.)
6.2 FETCH_HEAD — oxirgi olib kelingan narsa
Remote (masofaviy repo) — boshqa joydagi (masalan GitHub'dagi) nusxa. Undan yangi commitlarni olib kelish — git fetch. Bularni Remote darsida to'liq o'rganamiz. Hozir faqat FETCH_HEAD ni ko'rish uchun kichik sinov: «Bahor»ning nusxasini sinov-git/ ga olamiz. git clone — reponi nusxalash:
cd ~/kurs
git clone -q bahor sinov-git/bahor-nusxaKeyin asl «Bahor»ga somsa narxini qo'shib commit qildik va nusxaga qaytib, yangilikni olib keldik:
cd sinov-git/bahor-nusxa
git fetch
cat .git/FETCH_HEADFrom C:/Users/.../kurs/bahor
a0e2a64..5306a93 main -> origin/main
5306a93db0276940096ac030e29d8a8826e211bd branch 'main' of C:/Users/.../kurs/bahor
c1ecb39929fcba59b4a63316810fffb37e8e1d53 not-for-merge branch 'chore/eski-menyu-sinov' of C:/Users/.../kurs/bahorBirinchi qatorlar — git fetch ning o'z hisoboti: main a0e2a64 dan 5306a93 gacha yangilandi. origin/main — nusxadagi "asl repodagi main qayerda" degan eslatma; uni ham Remote darsida ochamiz. Keyingi qatorlar — .git/FETCH_HEAD faylining o'zi.
FETCH_HEAD — git fetch nimani olib kelganining ro'yxati: har branch uchun hash va qayerdan kelgani. Birinchi qator — asosiy natija, not-for-merge belgili qatorlar — qo'shimcha. git pull (u ham Remote darsida) aynan shu fayldan foydalanadi. Siz uni kamdan-kam o'qiysiz, lekin .git ichida ko'rsangiz — endi taniysiz.
Sinov tugadi: sinov-git/bahor-nusxa ni o'chirishingiz mumkin.
7. packed-refs — ref'lar bitta faylda
Oldingi darsda git gc obyektlarni bitta to'plamga yig'ishini ko'rdik. Ref'lar bilan ham shunday bo'ladi. «Bahor»da git gc ni ishga tushiramiz:
cd ~/kurs/bahor
git gc -q
ls .git/refs/heads .git/refs/tags.git/refs/heads:
chore
.git/refs/tags:Branch fayllari yo'q! heads da faqat bo'sh chore papkasi qoldi (branch nomidagi / papka yaratadi), tags umuman bo'sh. Branch'lar qayerga ketdi?
cat .git/packed-refs# pack-refs with: peeled fully-peeled sorted
c1ecb39929fcba59b4a63316810fffb37e8e1d53 refs/heads/chore/eski-menyu-sinov
5306a93db0276940096ac030e29d8a8826e211bd refs/heads/main
466a40f8f7939738aa26248689270b4388406a1f refs/tags/v1.0
^a0e2a6459d40b45c7e214df2ee02a359f41d1806Hamma ref'lar bitta packed-refs fayliga yozildi. ^a0e2a64… qatori — yuqoridagi annotated tag qaysi commitga ishora qilishi (tezroq topish uchun). Keyingi commitda Git main ni yana alohida faylga yozadi — alohida fayl packed-refs dagidan ustun turadi.
Bundan muhim xulosa: ref'larni o'qish uchun fayllarga emas, buyruqlarga tayaning. cat .git/refs/heads/main gc dan keyin "fayl topilmadi" deydi, git rev-parse main esa har doim ishlaydi. Darsda fayllarni faqat tushunish uchun ochdik.
Yana bir sabab bor. Rasmiy "BreakingChanges" hujjatida yozilishicha, kelajakdagi Git 3.0 da yangi repolar ref'larni "files" o'rniga reftable degan yangi formatda saqlaydi. Unda refs/heads/main kabi alohida fayllar bo'lmaydi. Sabablaridan biri Windows va macOS'ga tegishli: bu tizimlar fayl nomida katta-kichik harfni farqlamaydi. Shuning uchun "files" formatida faqat harf kattaligi bilan farq qiladigan ikki ref'ni (masalan Menyu va menyu branch'lari) saqlab bo'lmaydi. Chiqish sanasi hali belgilanmagan. git rev-parse va git show-ref esa ikkala formatda ham bir xil ishlaydi.
8. Ko'p uchraydigan xatolar
8.1 Detached HEAD'dan qo'rqish
Detached HEAD — xato emas, rejim. Eski versiyani ko'rish, eski relizni tekshirish, tajriba qilish — hammasi shu rejimda bo'ladi. Faqat bitta qoida: bu yerda qilingan commitlarni chiqishdan oldin branch bilan saqlang.
8.2 Ogohlantirishni o'qimasdan chiqish
Warning: you are leaving 1 commit behind — eng muhim satr. Unda qutqarish buyrug'i tayyor yozilgan: git branch <new-branch-name> <hash>. Hashni nusxalab oling.
8.3 switch ga hash berish
fatal: a branch is expected, got commit 'f4238e7'switch faqat branch'larga o'tadi. Commitga borish uchun --detach kerak — hint qatori buni aytadi.
8.4 .git fayllarini qo'lda tahrirlash
echo hash > .git/refs/heads/main "ishlaydi", lekin Git'ning himoyasini chetlab o'tadi: jurnal (reflog) yozilmaydi, xato hash yozsangiz branch buziladi. Ref'ni o'zgartirish kerak bo'lsa — git reset, git branch -f kabi buyruqlar bor.
8.5 Mavjud bo'lmagan nom
fatal: Needed a single revisiongit rev-parse --verify topolmagan nom. Harflarni tekshiring va git show-ref bilan mavjud ref'lar ro'yxatiga qarang.
9. Mashqlar
1-mashq (oson): Kim kimga ishora qiladi?
«Bahor»da quyidagi buyruqlarning natijasini oldindan ayting, keyin tekshiring:
cat .git/HEADgit symbolic-ref HEADgit rev-parse --abbrev-ref HEADgit rev-parse HEADvagit rev-parse main— bir xilmi?
Ishora: «HEAD fayli» bo'limidagi diagramma.
Yechim
ref: refs/heads/main—HEADbranch nomini saqlaydi.refs/heads/main— o'sha narsa, Git buyrug'i orqali.main— qisqa branch nomi.- Ha, bir xil 40 belgili hash:
HEAD→main→ commit. Faqat detached holatda farq qilishi mumkin — undarev-parse --abbrev-ref HEADHEADdeb javob beradi.
2-mashq (o'rta): Vaqt sayohati
git log --oneline bilan «Bahor»ning ikkinchi commitini (osh narxi) toping. Bo'sh joylarni to'ldiring:
git switch f4238e7
git statusgit status birinchi qatorda HEAD [:detached] at f4238e7 deydi. Qaytish uchun: git switch [:main].
Ishora: «Eski commitga borish» bo'limi — switch hashni faqat maxsus flag bilan qabul qiladi.
Yechim
git switch --detach f4238e7
git status
git switch mainHEAD is now at f4238e7 Menyu: osh narxini qo'sh
HEAD detached at f4238e7
nothing to commit, working tree cleanOxirgi buyruq main ga qaytaradi. Detached holatda commit qilmagan bo'lsangiz, ogohlantirish chiqmaydi: Previous HEAD position was f4238e7 ... va Switched to branch 'main'.
3-mashq (qiyin): Yo'qolgan sinov
Stajyor Sardor shunday qildi:
git switch --detach HEAD~3
echo '<p>Chegirma 10%</p>' >> index.html
git commit -a -m "Bosh sahifa: chegirma yozuvini qo'sh"
git switch main
clearclear ekranni tozaladi va ogohlantirish ko'rinmay qoldi. Sardor chegirma commitini qaytarmoqchi.
- Commit omborda bormi?
ORIG_HEADyordam beradimi?- Hashni topish uchun eng oddiy yo'l qaysi va qanday qutqarasiz?
Ishora: «Maxsus HEAD'lar» bo'limi — qaysi buyruqlar ORIG_HEAD ni yozadi? «Detached holatda commit» bo'limidagi javobni ham eslang.
Yechim
- Ha. Commit obyekt sifatida yozilgan, unga hech qanday ref ishora qilmayapti, xolos.
- Yo'q.
ORIG_HEADnireset,merge,rebaseyozadi,switchesa yozmaydi. Unda Sardorning oldingi amallari (agar bo'lsa) turibdi. - Hash kerak. Eng oddiy yo'l —
git reflog: uHEADning har bir harakatini hash bilan yozib boradi. Buyruqni Reflog darsida to'liq o'rganamiz, lekin hozir ham yozib ko'rishingiz mumkin. Bizning sinovimizdagi choy commiti u yerda shunday qator bo'lib turibdi:c1ecb39 (chore/eski-menyu-sinov) HEAD@{8}: commit: Menyu: choy narxini qo'sh (sinov)(qavs ichidagi nom — biz unga keyin qo'ygan branch). Sardor ham chegirma xabari yozilgan qatorni topadi va uning boshidagi hash bilan qutqaradi:git branch chegirma <hash>.
4-mashq: Portfolio qadami — portfolio'ning birinchi versiyasi
kurs/portfoliodacat .git/HEADvagit rev-parse HEAD mainni ishga tushiring. Natijani tushuntiring.git log --onelinebilan birinchi commitingizni toping (eng pastki qator).- Unga detached holatda o'ting:
git switch --detach <hash>.git statusnima deydi? sayt/index.htmlni brauzerda oching — portfolio 07-qism boshida qanday edi? Hozirgi bilan solishtiring.mainga qayting va brauzerda sahifani yangilang.
mashqlar repo: shu darsning 1–3-mashq javoblarini mashqlar/07/12-head-refs/javoblar.md ga yozing va commit qiling: 07/12: HEAD va refs mashqlari javoblarini qo'sh.
Yechim
cd ~/kurs/portfolio
cat .git/HEAD
git rev-parse HEAD main
git log --oneline
git switch --detach 63190c1
git status
git switch mainBirinchi commit hashi o'rniga o'zingiznikini qo'ying. Biz qisqa portfolio'ga bitta commit qo'shib sinadik. git switch --detach HEAD~1 va git status natijasi:
HEAD is now at 63190c1 Portfolio: 06-qism oxiridagi holat
HEAD detached at 63190c1
nothing to commit, working tree cleanmain ga qaytganda:
Previous HEAD position was 63190c1 Portfolio: 06-qism oxiridagi holat
Switched to branch 'main'Birinchi qadamda ref: refs/heads/main va ikki bir xil hash chiqadi: HEAD → main → oxirgi commit. Detached holatda fayllar birinchi commitdagi holatga qaytadi — keyingi darslardagi o'zgarishlar sahifada ko'rinmaydi. main ga qaytgach hammasi joyiga keladi. Hech narsa yo'qolmadi, chunki detached holatda commit qilmadingiz.
10. Real ishda
- Terminal va VS Code hozirgi branch'ni
HEADdan o'qiydi. VS Code pastki panelida branch nomi yoki (detached bo'lsa) commit hashi ko'rinadi. - CI tizimlari — har yangi commitda kodni avtomatik tekshiradigan serverlar (masalan GitHub Actions, qism oxirida o'rganamiz). Ular reponi ko'pincha detached HEAD holatida oladi: aniq bir commit tekshiriladi. Loglarda
HEAD is now at …ni ko'rsangiz — bu shu. - Skriptlarda
git rev-parse --abbrev-ref HEAD(branch nomi) vagit rev-parse --short HEAD(versiya uchun qisqa hash) juda ko'p ishlatiladi — masalan saytning pastki qismida "versiya: a0e2a64" yozish uchun. - Intervyu savollari: "Branch aslida nima?" (commit hashi yozilgan fayl), "Detached HEAD nima va undan qanday chiqiladi?", "
HEAD~1vaORIG_HEADfarqi?" Bu darsdan keyin uchalasiga javob bera olasiz.
Xulosa
- Branch — ref: ichida commit hashi yozilgan fayl (
.git/refs/heads/main); commit uni oldinga suradi. HEAD— symbolic ref: odatdaref: refs/heads/main, ya'ni "hozirgi branch".- Detached HEAD —
HEADto'g'ridan-to'g'ri commitni ko'rsatadi; sayr uchun xavfsiz, commitlarni esagit branchbilan saqlang. git rev-parse— nomdan hashga; ref'larni fayllardan emas, buyruqlardan o'qing (packed-refs, kelajakdagi reftable).ORIG_HEADoxirgi reset/merge/rebase'dan oldingi joyni eslaydi;FETCH_HEAD— oxirgi fetch natijasi.
Keyingi dars: .gitattributes va qator oxirlari (CRLF/LF) — Windows'dagi LF will be replaced by CRLF ogohlantirishini butunlay tartibga solamiz.
Manbalar
- Pro Git kitobi: "Git Internals — Git References" — git-scm.com/book
- Git hujjati: "git-rev-parse", "git-symbolic-ref", "git-switch", "gitrevisions" — git-scm.com/docs
- Git hujjati: "BreakingChanges" (Git 3.0 va reftable) — git-scm.com/docs/BreakingChanges
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!