IlmHamroh
JavaScript Full-stack/7-qism. Git va GitHub asoslari23/36-dars21 daqiqa
Mundarija (37)

Git reflog: yo'qolgan commitni qaytarish va "favqulodda yordam" retseptlari

Qisqacha: Git'da commit qilingan narsa deyarli hech qachon darhol yo'qolmaydi. git reflog — HEAD qayerlarda bo'lganining kundaligi: reset --hard, o'chirilgan branch yoki amend dan oldingi commitning SHA'si shu yerda turadi. SHA'ni topib, git reset --hard HEAD@{1} yoki git branch <nom> <sha> bilan qaytarasiz. Yozuvlar sukut bo'yicha 90 kun (yetib bo'lmaydiganlari 30 kun) saqlanadi; hech qachon add qilinmagan o'zgarish esa haqiqatan yo'qoladi.

Bu darsda

  • git reflog chiqishini o'qiysiz va HEAD@{n} nimani bildirishini tushuntira olasiz.
  • reset --hard, o'chirilgan branch, amend va merge'dan keyin avvalgi holatni qaytarasiz.
  • Noto'g'ri branchga tushgan commitni kerakli branchga ko'chirasiz.
  • Push qilingan xatoni revert bilan, yo'qolgan stash va faylni git fsck bilan qutqarasiz.
  • Nima qancha vaqt saqlanishini (gc muddatlari) va nima umuman qaytmasligini bilasiz.

Oldin bilishingiz kerak: Xatoni tuzatish 2: reset va revert, HEAD, refs va detached HEAD, Stash: yarim ishni vaqtincha chetga olish.

1. Nega bu kerak?

Kechqurun soat o'n bir. Aziz «Bahor» menyusida ishlayapti. Reset va revert darsidagi buyruqni eslab, oxirgi commitni bekor qilmoqchi bo'ldi. Lekin HEAD~1 o'rniga HEAD~2 yozib yubordi. Ikki commit — manti va chuchvara narxlari — git log dan g'oyib bo'ldi. --hard bo'lgani uchun fayllardan ham.

Birinchi o'y: "Hammasi yo'qoldi. Qaytadan yozaman."

Shoshmang. Git'ning ichida uchoqlardagi "qora quti" kabi yozuvchi qurilma bor. Samolyotda nima bo'lsa ham, qora quti har bir harakatni yozib boradi. Git'da ham HEAD har safar bir joydan boshqa joyga o'tganda — commit, reset, branch almashtirish, merge — bu yozib qo'yiladi. Commit git log dan yo'qolgan bo'lishi mumkin, lekin qora qutidan emas.

Bu dars — dori qutisi. Avval qora qutini o'qishni o'rganamiz, keyin eng ko'p uchraydigan to'qqizta "baxtsiz hodisa" uchun tayyor retsept. Har retseptni biz sinov repoda haqiqatan bajardik — natijalar haqiqiy.

2. Reflog — HEAD kundaligi

2.1 git reflog ni o'qish

«Bahor» reposida oddiy tarixga qaraymiz:

bash
git log --oneline
text
d0dd8bb (HEAD -> main) Menyu: chuchvara narxini qo'sh
5a2cf1f Menyu: manti narxini qo'sh
07b061d Menyu: lag'mon narxini qo'sh
bd98d1b Bron: rahmat sahifasini qo'sh
b09fa2a Aloqa: sahifa yarat
9084599 Bosh sahifa: aloqa havolasini qo'sh
f4238e7 Menyu: osh narxini qo'sh
dab5bff Bahor: sayt tuzilmasini yarat

Endi reflog'ga:

bash
git reflog
text
d0dd8bb (HEAD -> main) HEAD@{0}: commit: Menyu: chuchvara narxini qo'sh
5a2cf1f HEAD@{1}: commit: Menyu: manti narxini qo'sh
07b061d HEAD@{2}: commit: Menyu: lag'mon narxini qo'sh
bd98d1b HEAD@{3}: commit: Bron: rahmat sahifasini qo'sh
b09fa2a HEAD@{4}: commit: Aloqa: sahifa yarat
9084599 HEAD@{5}: commit: Bosh sahifa: aloqa havolasini qo'sh
f4238e7 HEAD@{6}: commit: Menyu: osh narxini qo'sh
dab5bff HEAD@{7}: commit (initial): Bahor: sayt tuzilmasini yarat

Hozircha ikkalasi o'xshash, chunki biz faqat commit qildik. Har qator — HEAD'ning bitta harakati:

  • d0dd8bb — harakatdan keyin HEAD qaysi commitda turgani.
  • HEAD@{0} — "HEAD hozir", HEAD@{1} — "bitta harakat oldin", HEAD@{2} — "ikkita harakat oldin".
  • commit: — harakat turi. Keyin reset:, checkout:, merge kabilarni ham ko'rasiz.
  • Oxiri — izoh (commit xabari yoki qayerdan qayerga o'tilgani).

Reflog (reference log) — "havolalar jurnali": HEAD va har bir branch uchi qayerlarda bo'lganining ro'yxati. Farqni aniq tushunib oling: git log tarixning hozirgi shaklini ko'rsatadi — commitlar zanjirini. git reflog esa sizning harakatlaringizni — nima qilganingiz tarixini.

2.2 Vaqt bilan

Qachon bo'lganini ham ko'rish mumkin:

bash
git reflog -3 --date=iso
text
d0dd8bb (HEAD -> main) HEAD@{2026-10-10 09:10:00 +0500}: commit: Menyu: chuchvara narxini qo'sh
5a2cf1f HEAD@{2026-10-10 09:00:00 +0500}: commit: Menyu: manti narxini qo'sh
07b061d HEAD@{2026-10-02 10:12:00 +0500}: commit: Menyu: lag'mon narxini qo'sh

-3 — oxirgi uchta yozuv. Git vaqt bilan murojaat qilishni ham tushunadi: HEAD@{1.hour.ago} — "bir soat oldin HEAD qayerda edi", main@{yesterday} — "kecha main qayerda edi". "Ertalab ishlayotgan edi, keyin nimadir buzildi" degan holatda juda qulay.

2.3 Har branchning o'z reflogi

git reflog HEAD'nikini ko'rsatadi. Har branch uchun alohida jurnal ham bor: git reflog show main. Bu dars davomida uni o'chirilgan branch retseptida ko'rasiz.

Tekshirib ko'ring: git log da 6 ta commit, git reflog da esa 20 ta yozuv. Bu qanday bo'lishi mumkin?

Javob

Reflog commitlarni emas, HEAD harakatlarini yozadi. Branch almashtirish (checkout:), reset, merge — har biri alohida yozuv, garchi yangi commit yaratmasa ham. Bitta commitga ko'p marta qaytib kelish mumkin — u reflogda bir necha marta ko'rinadi.

3. Retsept 1: reset --hard dan qaytish

3.1 Baxtsiz hodisa

bash
git reset --hard HEAD~2
git log --oneline -2
text
HEAD is now at 07b061d Menyu: lag'mon narxini qo'sh
07b061d (HEAD -> main) Menyu: lag'mon narxini qo'sh
bd98d1b Bron: rahmat sahifasini qo'sh

Manti va chuchvara log dan yo'qoldi. Qora qutini ochamiz:

bash
git reflog -3
text
07b061d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~2
d0dd8bb HEAD@{1}: commit: Menyu: chuchvara narxini qo'sh
5a2cf1f HEAD@{2}: commit: Menyu: manti narxini qo'sh

Mana ular! Eng yangi yozuv — bizning xato reset: "HEAD~2 ga ko'childi". Undan oldingi HEAD@{1} — reset'dan oldingi holat, chuchvara commiti.

3.2 Qaytarish

Avval tekshiramiz — aynan shu commit kerakmi:

bash
git show --oneline --stat HEAD@{1}
text
d0dd8bb Menyu: chuchvara narxini qo'sh
 menyu/index.html | 1 +
 1 file changed, 1 insertion(+)

Ha. Endi reset'ning o'zi bilan orqaga qaytamiz:

bash
git reset --hard HEAD@{1}
git log --oneline -3
text
HEAD is now at d0dd8bb Menyu: chuchvara narxini qo'sh
d0dd8bb (HEAD -> main) Menyu: chuchvara narxini qo'sh
5a2cf1f Menyu: manti narxini qo'sh
07b061d Menyu: lag'mon narxini qo'sh

Hammasi joyida. HEAD@{1} o'rniga SHA'ni ham yozish mumkin: git reset --hard d0dd8bb. SHA — ishonchliroq: har yangi harakat bilan {1} raqami suriladi, SHA esa o'zgarmaydi.

3.3 Qisqa yo'l: ORIG_HEAD

HEAD va refs darsida ORIG_HEAD ni ko'rgan edik. Git uni "xavfli" buyruqlardan (reset, merge, rebase) oldin yozib qo'yadi. Xuddi shu xatoni takrorlab, faylga qaraymiz:

bash
git reset --hard HEAD~2
cat .git/ORIG_HEAD
git reset --hard ORIG_HEAD
text
HEAD is now at 07b061d Menyu: lag'mon narxini qo'sh
d0dd8bb32588d674bbfefd88b65062f6e94010ee
HEAD is now at d0dd8bb Menyu: chuchvara narxini qo'sh

ORIG_HEAD — reset'dan oldingi SHA. Lekin u faqat oxirgi xavfli buyruqni eslaydi: keyingisi uni ustidan yozadi. Xato darhol sezilsa — ORIG_HEAD; kechroq bo'lsa — reflog.

4. Retsept 2: o'chirilgan branchni tiklash

Aziz feature/bron-forma branchida ikki commit qildi va main ga qaytdi. Keyin "keraksiz" deb o'chirmoqchi bo'ldi:

bash
git branch -d feature/bron-forma
text
error: the branch 'feature/bron-forma' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/bron-forma'
hint: Disable this message with "git config set advice.forceDeleteBranch false"

Git ogohlantirdi: "branch to'liq birlashtirilmagan" — unda boshqa joyda yo'q commitlar bor (Branch nima). Aziz o'qimasdan katta -D bilan o'chirdi:

bash
git branch -D feature/bron-forma
text
Deleted branch feature/bron-forma (was bf0c0cf).

Birinchi qutqaruvchi — shu xabarning o'zi: was bf0c0cf. Terminal hali ochiq bo'lsa, shu SHA yetarli. Yopilgan bo'lsa — reflog:

bash
git reflog -4
text
d0dd8bb (HEAD -> main) HEAD@{0}: checkout: moving from feature/bron-forma to main
bf0c0cf HEAD@{1}: commit: Bron: ism maydonini qo'sh
638ddc8 HEAD@{2}: commit: Bron: forma skeletini qo'sh
d0dd8bb (HEAD -> main) HEAD@{3}: checkout: moving from main to feature/bron-forma

Pastdan tepaga o'qiymiz: main dan feature/bron-forma ga o'tildi, ikki commit qilindi, main ga qaytildi. Branchning oxirgi commiti — main ga qaytishdan oldingi yozuv, bf0c0cf. Branchni o'sha commitda qayta yaratamiz:

bash
git branch feature/bron-forma HEAD@{1}
git log --oneline -3 feature/bron-forma
text
bf0c0cf (feature/bron-forma) Bron: ism maydonini qo'sh
638ddc8 Bron: forma skeletini qo'sh
d0dd8bb (HEAD -> main) Menyu: chuchvara narxini qo'sh

Branch qaytdi — ikkala commiti bilan. Nega bu ishladi? Branch nima darsini eslang: branch — shunchaki commitga yopishtirilgan yorliq. O'chirish faqat yorliqni oladi. Commitlar .git/objects da qoladi, biz esa yorliqni qayta yopishtirdik.

Bir nozik nuqta. Branch o'chirilganda uning o'z reflogi ham o'chadi:

bash
git reflog show feature/bron-forma
text
bf0c0cf (feature/bron-forma) feature/bron-forma@{0}: branch: Created from HEAD@{1}

Yangi branch jurnali bitta yozuvdan boshlandi — eski tarixi yo'q. Shuning uchun o'chirilgan branchni doim HEAD reflogidan qidirasiz.

5. Retsept 3: noto'g'ri branchga commit

5.1 Yangi branch kerak edi

Aziz aloqa sahifasiga manzil qo'shib, commit qildi. Keyin sezdi: bu yangi vazifa edi, alohida branchda bo'lishi kerak edi, u esa main da turibdi.

bash
git log --oneline -2
text
f111dd8 (HEAD -> main) Aloqa: manzilni qo'sh
d0dd8bb Menyu: chuchvara narxini qo'sh

Ikki qadam: avval joriy joyda yangi branch yorlig'ini qo'yamiz, keyin main ni bir commit orqaga suramiz:

bash
git branch fix/aloqa-manzil
git reset --hard HEAD~1
git log --oneline -1
git log --oneline -2 fix/aloqa-manzil
text
HEAD is now at d0dd8bb Menyu: chuchvara narxini qo'sh
d0dd8bb (HEAD -> main) Menyu: chuchvara narxini qo'sh
f111dd8 (fix/aloqa-manzil) Aloqa: manzilni qo'sh
d0dd8bb (HEAD -> main) Menyu: chuchvara narxini qo'sh

git branch (switch -c emas!) yorliqni qo'yadi, lekin bizni main da qoldiradi. Commit endi fix/aloqa-manzil da, main esa tozalandi.

flowchart LR
  A["main: ...d0dd8bb<br/>f111dd8 (xato)"] --> B["git branch<br/>fix/aloqa-manzil"]
  B --> C["git reset --hard<br/>HEAD~1"]
  C --> D["main: d0dd8bb<br/>fix/aloqa-manzil: f111dd8"]

Nimaga qarang: tartib muhim. Avval reset qilsangiz, commitga yorliq qolmaydi — keyin uni reflogdan qidirishga to'g'ri keladi.

5.2 Mavjud boshqa branch kerak edi

Yana bir holat: Aziz bron shartlari sahifasini main ga commit qildi, aslida u allaqachon bor feature/bron-forma branchiga tegishli edi. Bu safar cherry-pick bilan ko'chiramiz, keyin main ni tozalaymiz:

bash
git switch feature/bron-forma
git cherry-pick main
git switch main
git reset --hard HEAD~1
text
Switched to branch 'feature/bron-forma'
[feature/bron-forma 5f7cc94] Bron: shartlar sahifasini qo'sh
 Date: Sat Oct 10 11:10:00 2026 +0500
 1 file changed, 1 insertion(+)
 create mode 100644 bron/shartlar.html
Switched to branch 'main'
HEAD is now at d0dd8bb Menyu: chuchvara narxini qo'sh

git cherry-pick main — "main ning oxirgi commitini ol". Cherry-pick darsida aytganimizdek, branch nomi yozilsa, uning faqat uchidagi commit olinadi — aynan bizga kerak bo'lgani.

Diqqat: 3-retseptning ikkala varianti ham main tarixini qayta yozadi. Bu faqat xato commit hali hech kimga yuborilmagan bo'lsa mumkin. Yuborilgan bo'lsa — 6-retsept.

6. Retsept 4: amend ni bekor qilish

Xatoni tuzatish 1 darsida commit --amend oxirgi commitni "tuzatishini" ko'rgan edik. Aslida u eski commitni o'zgartirmaydi — yangisini yaratadi. Aziz "Menyu: ko'k choy narxini qo'sh" commitiga adashib somsa narxini ham qo'shib yubordi:

bash
git add menyu/index.html
git commit --amend --no-edit
git reflog -2
text
[main 480e448] Menyu: ko'k choy narxini qo'sh
 Date: Sat Oct 10 12:00:00 2026 +0500
 1 file changed, 2 insertions(+)
480e448 (HEAD -> main) HEAD@{0}: commit (amend): Menyu: ko'k choy narxini qo'sh
7dfc18c HEAD@{1}: commit: Menyu: ko'k choy narxini qo'sh

Reflog ikkala versiyani ko'rsatyapti: 7dfc18c — asl, 480e448 — amend'dan keyingisi. Asl commitga qaytamiz, lekin o'zgarishlarni yo'qotmaymiz — reset darsidagi --soft:

bash
git reset --soft HEAD@{1}
git status -s
git log --oneline -1
text
M  menyu/index.html
7dfc18c (HEAD -> main) Menyu: ko'k choy narxini qo'sh

Commit asl holatiga qaytdi. Somsa qatori esa qutida turibdi — uni alohida commit qilish yoki olib tashlash mumkin.

7. Retsept 5: merge'ni bekor qilish

Aziz feature/bron-forma ni main ga birlashtirdi, keyin Jasur aka "bron hali tayyor emas" dedi. Merge hali yuborilmagan:

bash
git merge --no-ff --no-edit feature/bron-forma
git reset --hard ORIG_HEAD
git log --oneline -1
text
Merge made by the 'ort' strategy.
 bron/index.html    | 2 ++
 bron/shartlar.html | 1 +
 2 files changed, 3 insertions(+)
 create mode 100644 bron/shartlar.html
HEAD is now at 7dfc18c Menyu: ko'k choy narxini qo'sh
7dfc18c (HEAD -> main) Menyu: ko'k choy narxini qo'sh

merge ham ORIG_HEAD ni yozadi — merge'dan oldingi holat. reset --hard ORIG_HEAD hammasini ortga qaytaradi. rebase dan keyin ham xuddi shunday ishlaydi (Rebase).

8. Retsept 6: push qilingan xato — revert

Aziz osh narxini 3 500 deb yozdi (bitta nol tushib qoldi) va commitni GitHub'ga yuborib ulgurdi. Endi reset bilan tarixni qayta yozish mumkin emas — boshqalar bu commitni allaqachon olgan bo'lishi mumkin (rebase oltin qoidasi aynan shu haqda).

Xavfsiz yo'l — Reset va revert darsidagi revert: teskari o'zgarishli yangi commit.

bash
git revert --no-edit HEAD
git log --oneline -3
text
[main 330abfe] Revert "Menyu: osh narxini yangila"
 Date: Sat Oct 10 13:05:00 2026 +0500
 1 file changed, 1 deletion(-)
330abfe (HEAD -> main) Revert "Menyu: osh narxini yangila"
0b1109d Menyu: osh narxini yangila
7dfc18c Menyu: ko'k choy narxini qo'sh

--no-edit — muharrirni ochmasdan, Git taklif qilgan xabarni qabul qil. Xato commit tarixda qoldi, lekin uning ta'siri bekor qilindi. Keyin to'g'ri narxni yangi commit bilan yozasiz va ikkalasini yuborasiz.

9. Retsept 7: drop qilingan stash

Stash darsida drop stash SHA'sini chiqarishini ko'rgan edik. Aziz chegirma g'oyasini stash qildi va adashib o'chirdi:

bash
git stash push -m "chegirma g'oyasi"
git stash drop
text
Saved working directory and index state On main: chegirma g'oyasi
Dropped refs/stash@{0} (91e0302aa12706a8ea2843a2296fd09b467c798f)

Terminal ochiq bo'lsa — qavs ichidagi SHA bilan darhol: git stash apply 91e0302.... Yopilgan bo'lsa-chi? Stash reflogda yo'q — u o'chirilgan. Bu yerda boshqa asbob kerak: git fsck.

git fsck (file system check) — Git bazasining "tibbiy ko'rigi". U .git/objects dagi barcha obyektlarni tekshiradi. --lost-found bilan esa hech narsa ko'rsatmayotgan, "yetim" obyektlarni topadi:

bash
git fsck --lost-found
text
dangling commit 02a2b04872e51f0e242a5d80d9dfb9ad969bef07
dangling commit 3909f7935953a543a74ce7056b85d1a5ab59cb6a
dangling commit 480e4480558c84c4cd74d357a7e78528560fa7a4
dangling commit 91e0302aa12706a8ea2843a2296fd09b467c798f

Dangling — "osilib qolgan": hech bir branch, tag yoki boshqa obyekt ko'rsatmaydigan commit. To'rttasi bor. Qaysi biri stash? Xabarlarini ko'ramiz — --no-walk "faqat shu commitlarning o'zini ko'rsat, otalariga o'tma" degani:

bash
git log --oneline --no-walk 02a2b04 3909f79 480e448 91e0302
text
91e0302 On main: chegirma g'oyasi
02a2b04 Merge branch 'feature/bron-forma'
480e448 Menyu: ko'k choy narxini qo'sh
3909f79 Bron: shartlar sahifasini qo'sh

Ro'yxatda darsdagi boshqa "baxtsiz hodisalar" ham bor: bekor qilingan merge, amend qilingan commit, main dan olib tashlangan shartlar commiti. Stash — On main: chegirma g'oyasi. Uni qaytaramiz:

bash
git stash apply 91e0302
git status -s
text
 M index.html

(apply ning to'liq git status chiqishini qisqartirdik.) Chegirma qatori papkaga qaytdi.

10. Retsept 8: add qilingan, lekin commit qilinmagan fayl

Aziz yangi tadbirlar.html sahifasini yaratdi va git add qildi. Commit qilmasdan, boshqa ishni tozalash uchun git reset --hard yozdi:

bash
git reset --hard
ls tadbirlar.html
text
HEAD is now at 330abfe Revert "Menyu: osh narxini yangila"
ls: cannot access 'tadbirlar.html': No such file or directory

Fayl yo'q. Commit ham yo'q — reflog yordam bermaydi. Lekin bitta umid bor. Git ichkaridan darsida ko'rgansiz: git add fayl mazmunini darhol .git/objects ga blob qilib yozadi. Blob hali o'sha yerda:

bash
git fsck --lost-found
text
dangling commit 02a2b04872e51f0e242a5d80d9dfb9ad969bef07
dangling blob 1770056af463d7af599325e42ea7a13eeb3efe9a
dangling commit 3909f7935953a543a74ce7056b85d1a5ab59cb6a
...

Yangi qator — dangling blob. --lost-found ularni .git/lost-found/other/ papkasiga ham yozib qo'yadi. Mazmuniga qaraymiz:

bash
git show 1770056
text
<h1>Yangi sahifa: tadbirlar</h1>

Aynan o'sha. Faylni qayta yozamiz — > bilan (Oqimlar va yo'naltirish):

bash
git show 1770056 > tadbirlar.html
git status -s
text
?? tadbirlar.html

Blob faqat mazmunni saqlaydi, fayl nomini emas. Shuning uchun ko'p blob bo'lsa, har birini ochib, qaysi fayl ekanini mazmunidan taniysiz.

11. Retsept 9: qaytarib bo'lmaydigan holat

Endi halol gap. Aziz aloqa sahifasiga bir qator yozdi, add ham, commit ham qilmadi va git reset --hard yozdi. git fsck --lost-found ni tekshirdik — ro'yxat oldingisi bilan bir xil, yangi blob yo'q.

Git hech qachon ko'rmagan narsani qaytara olmaydi. Hech qachon add, commit yoki stash qilinmagan o'zgarish reset --hard, restore yoki checkout -- fayl dan keyin butunlay yo'qoladi. Bunday holatda yagona umid — VS Code'ning o'z tarixi (Timeline paneli) yoki muharrirda Ctrl + Z.

Bundan oddiy qoida chiqadi: tez-tez commit qiling. Commit qilingan narsa deyarli yo'qolmaydi. Commit qilinmagan narsa — himoyasiz.

12. Qancha vaqt saqlanadi? gc muddatlari

12.1 Uchta muddat

Yetim commitlar abadiy qolmaydi. Git vaqti-vaqti bilan "tozalash" — gc (garbage collection, axlat yig'ish) — o'tkazadi. U ko'plab buyruqlardan keyin avtomatik ishga tushadi (git gc --auto). git-scm.com hujjatidagi sukut qiymatlari:

Sozlama Sukut Ma'nosi
gc.reflogExpire 90 kun oddiy reflog yozuvlari shuncha saqlanadi
gc.reflogExpireUnreachable 30 kun hozirgi tarixdan yetib bo'lmaydigan commitlarga oid yozuvlar
gc.pruneExpire 2 hafta hech narsa ko'rsatmaydigan obyektlar o'chirilishidan oldingi muhlat

Ya'ni reset --hard bilan "yo'qolgan" commit kamida 30 kun reflogda turadi. Reflogdan chiqqach, yana ikki hafta muhlat bor. Avtomatik gc esa har safar emas, faqat .git/objects da alohida (siqilmagan) obyektlar ko'payganda ishga tushadi (gc.auto — sukut bo'yicha 6700 ta). Amalda — bir necha hafta vaqtingiz bor.

Bu sozlamalar sizda o'rnatilmagan — sinovda git config gc.reflogExpire hech narsa chiqarmadi (chiqish kodi 1). Demak, sukut qiymatlari ishlaydi.

12.2 Majburiy tozalash — xavfli

Muddatlarni kutmasdan tozalash mumkin. Sinov repoda buni qilib ko'rdik — oqibatini ko'rish uchun:

bash
git cat-file -t 91e0302
git reflog expire --expire-unreachable=now --all
git gc --prune=now --quiet
git cat-file -t 91e0302
text
commit
fatal: git cat-file: could not get object info

Tozalashdan oldin chegirma stashi bor edi (commit). Keyin — yo'q: "obyekt haqida ma'lumot olib bo'lmadi". Endi uni hech narsa qaytarmaydi.

Diqqat: Internetda "repo hajmini kamaytirish" uchun shu buyruqlar tavsiya qilinadi. Ularni favqulodda holatda — biror narsani qutqarmoqchi bo'lganingizda — hech qachon yozmang. Qutqaruv tugamaguncha gc ga tegmang.

12.3 Reflog — faqat sizniki

Reflog lokal. U GitHub'ga yuborilmaydi va git clone bilan kelmaydi. «Bahor» reposini nusxalab ko'rdik:

bash
git clone -q bahor bahor-nusxa
cd bahor-nusxa
git reflog
text
330abfe (HEAD -> main, origin/main, origin/HEAD) HEAD@{0}: clone: from C:/Users/.../kurs/bahor

(Yo'lni ... bilan qisqartirdik.) Asl repoda yigirmadan ortiq yozuv bor edi, nusxada — bitta. Demak, hamkasbingizning kompyuterida yo'qolgan commitni sizning reflogingiz qutqarmaydi, va aksincha. git clone ni Remote darsida batafsil o'rganamiz.

13. Qaysi retsept? Xarita

flowchart TD
  A["Nima yo'qoldi?"] --> B{"Commit qilinganmi?"}
  B -- ha --> C{"Push qilinganmi?"}
  C -- ha --> D["revert"]
  C -- yo'q --> E["reflog → reset<br/>yoki branch"]
  B -- yo'q --> F{"add yoki stash<br/>qilinganmi?"}
  F -- ha --> G["fsck --lost-found"]
  F -- yo'q --> H["Git'da yo'q:<br/>VS Code Timeline"]

Nimaga qarang: birinchi savol doim bitta — "commit qilinganmi?". Chap tomondagi har qadam qutqarishni osonlashtiradi, o'ng tomonga o'tgan sari imkon kamayadi.

Maslahat: Xavfli buyruqdan oldin (katta rebase, reset --hard, tarixni tozalash) bir soniyalik sug'urta qiling: git branch zaxira. Yorliq commitlarni ushlab turadi — reflogni qidirish ham kerak bo'lmaydi. Ish tugagach, git branch -D zaxira.

14. Ko'p uchraydigan xatolar

14.1 PowerShell'da HEAD@{1}

Git Bash'da hammasi ishlaydi. Lekin o'sha buyruqlarni Windows PowerShell'da (Windows'dagi standart 5.1 versiya) yozsangiz, sinovda shunday chiqdi:

powershell
git show --oneline --stat HEAD@{1}
text
fatal: ambiguous argument 'HEAD@': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Tarjimasi: "noaniq argument HEAD@: noma'lum reviziya yoki ishchi papkada yo'q yo'l". Git {1} ni umuman olmadi! git reset --hard HEAD@{1} esa yanada g'alati xato beradi — error: unknown switch `e' va uzun foydalanish yo'riqnomasi. Sabab: PowerShell'da jingalak qavslar — kod bloki. U {1} ni Git'ga matn sifatida bermaydi, o'rniga o'zining -encodedCommand ... argumentlarini qo'yib yuboradi. **Tuzatish:** bittalik qo'shtirnoq — git reset --hard 'HEAD@{1}' (sinovda git show --oneline -s 'HEAD@{1}' to'g'ri commitni ko'rsatdi) — yoki Git Bash ishlating. Kursda buyruqlar Git Bash uchun.

14.2 Raqam surilib ketdi

Aziz reflogni ko'rdi, keyin yana bir git switch qildi va git reset --hard HEAD@{1} yozdi. Lekin switch reflogga yangi yozuv qo'shdi — {1} endi boshqa narsani ko'rsatadi. Tuzatish: reflogdan SHA'ni nusxalang: git reset --hard d0dd8bb. SHA surilmaydi.

14.3 Qutqarayotib yangi ishni yo'qotish

Qutqarishda ishchi papkada saqlanmagan yangi o'zgarishlar bo'lsa, reset --hard ularni o'chiradi — yangi baxtsiz hodisa! Qutqarishdan oldin git status ga qarang. Toza bo'lmasa — avval git stash -u.

15. Mashqlar

1-mashq (oson): Reflogni o'qing

text
b09fa2a (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
3b4cb8f HEAD@{1}: commit: Menyu: somsa narxini qo'sh
07b061d (feature/dizayn) HEAD@{2}: checkout: moving from feature/dizayn to main
  1. Oxirgi harakat nima bo'lgan?
  2. Reset'dan oldin HEAD qaysi commitda edi?
  3. Oxirgi holatga qaytish uchun qaysi buyruq?
Yechim
  1. reset — HEAD uch commit orqaga surilgan.
  2. 3b4cb8f — "Menyu: somsa narxini qo'sh". HEAD@{1} — bitta harakat oldin.
  3. git reset --hard 3b4cb8f (yoki HEAD@{1}, yoki darhol bo'lsa ORIG_HEAD).

2-mashq (o'rta): Bo'sh joylarni to'ldiring

Aziz main da commit qildi, lekin bu fix/aloqa-manzil degan yangi branchda bo'lishi kerak edi. Commit hali yuborilmagan.

bash
git  fix/aloqa-manzil
git reset --hard 
git log --oneline -1
git log --oneline -1 fix/aloqa-manzil

Ishora: yorliq qo'yadigan, lekin branchni almashtirmaydigan buyruq; main ni bitta commit orqaga surish (Reset va revert).

Yechim
bash
git branch fix/aloqa-manzil
git reset --hard HEAD~1
git log --oneline -1
git log --oneline -1 fix/aloqa-manzil

Birinchi log — main xato commitdan oldingi holatda. Ikkinchisi — xato commit endi fix/aloqa-manzil da. Tartibni almashtirmang: avval reset qilsangiz, commitni reflogdan qidirishga to'g'ri keladi.

3-mashq (qiyin): Uch baxtsiz hodisa

Har biri uchun retsept (buyruqlar ketma-ketligi) yozing va nega aynan shu ekanini tushuntiring:

  1. Sardor git branch -D tolov qildi. Terminalni yopdi. Branchda 5 commit bor edi.
  2. Sardor GitHub'ga yuborilgan main dagi oxirgi commit saytni buzganini sezdi.
  3. Sardor yangi rasmlar.html ni git add qildi, keyin git stash drop o'rniga git reset --hard yozdi.

Ishora: «Qaysi retsept? Xarita» diagrammasi, «O'chirilgan branchni tiklash», «Push qilingan xato» va «add qilingan, lekin commit qilinmagan fayl» retseptlari.

Yechim
  1. git reflog — checkout: moving from tolov to ... qatorini topadi; undan oldingi yozuvning SHA'si — branch uchi. git branch tolov <sha>, keyin git log --oneline -5 tolov bilan tekshiradi. Branch o'z reflogi bilan birga o'chgan, shuning uchun HEAD reflogidan qidiriladi.
  2. git revert HEAD va yangi commitni yuborish. Push qilingan commitni reset bilan olib tashlab bo'lmaydi — boshqalar tarixi buziladi.
  3. git fsck --lost-found → dangling blob <sha> → git show <sha> bilan mazmunini tekshiradi → git show <sha> > rasmlar.html. add faylni blob qilib yozgani uchun qutqarish mumkin. add qilinmaganda — imkon yo'q edi.

4-mashq: Portfolio qadami — xavfsiz mashq

Portfolio'ingizda qutqarishni xavfsiz sinab ko'ring: vaqtinchalik branchda, haqiqiy ishga tegmasdan.

  1. git switch -c chore/qutqarish-sinov va bitta sinov qatori bilan commit qiling.
  2. git reset --hard HEAD~1 — commit "yo'qoldi". git reflog -3 bilan uni toping va qaytaring.
  3. main ga qaytib, git branch -D chore/qutqarish-sinov bilan branchni o'chiring. Reflogdan branchni qayta tiklang.
  4. Oxirida branchni butunlay o'chiring. main ga hech narsa tegmaganini git log --oneline bilan tekshiring.
Yechim
bash
cd ~/kurs/portfolio
git switch -c chore/qutqarish-sinov
echo '<p>Sinov</p>' >> sayt/index.html
git add sayt/index.html
git commit -m "Sinov: vaqtinchalik qator qo'sh"
git reset --hard HEAD~1
git reflog -3
git reset --hard HEAD@{1}
git switch main
git branch -D chore/qutqarish-sinov
git reflog -1
git branch chore/qutqarish-sinov HEAD@{1}
git log --oneline -1 chore/qutqarish-sinov
git branch -D chore/qutqarish-sinov
git log --oneline

Biz qisqa portfolio nusxasida sinadik. Reset'dan keyingi git reflog -3:

text
1aaefc2 (HEAD -> chore/qutqarish-sinov, main) HEAD@{0}: reset: moving to HEAD~1
33fd86f HEAD@{1}: commit: Sinov: vaqtinchalik qator qo'sh
1aaefc2 (HEAD -> chore/qutqarish-sinov, main) HEAD@{2}: checkout: moving from main to chore/qutqarish-sinov

Branch o'chirilgach, git reflog -1 — checkout: moving from chore/qutqarish-sinov to main, demak HEAD@{1} — branch uchi. Tiklangan branch 33fd86f Sinov: vaqtinchalik qator qo'sh ni ko'rsatadi, oxirgi git log --oneline esa faqat ikki main commitini (1aaefc2 Bosh sahifa: footer qo'sh va 63190c1 Portfolio: 06-qism oxiridagi holat). SHA'lar sizda boshqacha. Bu mashqni bir marta qo'lingiz bilan qilgan bo'lsangiz, haqiqiy baxtsiz hodisada vahima qilmaysiz.

16. Real ishda

  • Har bir tajribali dasturchi kamida bir marta reflog bilan "hayotini saqlab qolgan". Katta rebase buzilganda, noto'g'ri branch o'chirilganda — birinchi buyruq git reflog.
  • "Oh Shit, Git!?!" — shunday retseptlar to'plamiga bag'ishlangan mashhur sayt (ohshitgit.com). Retseptlarning ko'pi aynan shu darsdagi buyruqlarga tayanadi.
  • Jamoada: push qilingan tarixni reset + majburiy push bilan "tuzatish" — jiddiy xato hisoblanadi. Umumiy branchda — faqat revert. Majburiy push va uning xavfsiz shaklini Ajralgan tarix darsida ko'rasiz.
  • Intervyuda: "reset --hard qilib yubordim, commitni qanday qaytaraman?" — klassik savol. Javob: git reflog, SHA'ni topish, git reset --hard <sha>.

Xulosa

  • git reflog — HEAD harakatlari kundaligi; HEAD@{n} — n ta harakat oldingi holat. SHA — ishonchliroq.
  • reset --hard, merge, amend dan qaytish: reflogdan SHA → reset (--hard yoki --soft); darhol bo'lsa — ORIG_HEAD.
  • O'chirilgan branch: HEAD reflogidan uchini topib, git branch <nom> <sha>.
  • Noto'g'ri branchdagi commit: git branch (yoki cherry-pick) + reset --hard HEAD~1; push qilingan xato — faqat revert.
  • Yo'qolgan stash va add qilingan fayl — git fsck --lost-found; hech qachon add qilinmagan o'zgarish qaytmaydi.
  • Sukut muddatlari: reflog 90 kun, yetib bo'lmaydigan yozuvlar 30 kun, yetim obyektlar yana 2 hafta; reflog lokal.

Keyingi dars: Worktree: bitta repoda parallel ishlash — stash qilmasdan, boshqa branchni alohida papkada ochib, ikki ishni bir vaqtda olib borishni o'rganamiz.

Manbalar

  • Git hujjati: "git-reflog", "git-fsck", "git-gc" va gc.* sozlamalari — git-scm.com/docs
  • Pro Git kitobi: "Git Internals — Maintenance and Data Recovery" — git-scm.com/book
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Git reflog: yo'qolgan commitni qaytarish va "favqulodda yordam" retseptlari — IlmHamroh