6 β Orqaga qaytish: restore, reset, revert¶
β¬ οΈ Oldingi: 05 β Tarixni o'qish: log, diff, show Β· π README Β· Keyingi: 07 β Branch β shoxlar β‘οΈ
Bu bobda: xato qilganda orqaga qaytishni o'rganamiz. Working zonadagi o'zgarishni
git restorebilan tashlashni, noto'g'riaddqilgannigit restore --stagedbilan staging'dan (commitga tayyorlanadigan oraliq zona) chiqarishni,git resetning uch turini (--soft,--mixed,--hard) va ularning uch zonaga ta'sirini, allaqachon ulashilgan tarixni xavfsiz bekor qiluvchigit revertni, oxirgi commitni tuzatuvchigit commit --amendni ko'rib chiqamiz. Eng muhimi β qaysi vosita qachon ishlatiladi va--hardkabi xavfli buyruqlardan qanday ehtiyot bo'lish kerakligini tushunamiz.
Muammo¶
Tasavvur qiling: diplom ishingiz uchun sayt yozyapsiz. Kecha kechqurun index.html faylini ochib, sarlavhani "tuzatmoqchi" bo'ldingiz β yarim soat o'ynaganingizdan keyin sayt umuman ishlamay qoldi. Endi esa nima o'zgartirganingizni ham eslay olmaysiz. Yuragingiz orziqib ketdi: "Hammasi buzildi, qaytadan yozaman shekilli...".
Yana bir holat: jamoaviy loyihada ishlayapsiz. git add . deb yozdingiz β va shoshilganingizdan, ichida parolingiz turgan config.txt faylini ham qo'shib yubordingiz. Hali commit qilmadingiz, lekin fayl staging'da turibdi. Uni u yerdan qanday chiqarib olish kerak?
Uchinchi holat: commit qildingiz, lekin keyin angladingiz β bu commit butunlay xato edi. Yoki commit xabarida xatolik bor: "Qoshildi: feacher" deb yozib yuboribsiz.
Bularning hammasi β kundalik ish. Git xato qilmaslik uchun emas, xatoni tuzatish uchun yaratilgan. Bu bobda Git sizga bergan "orqaga qaytish" tugmalarini o'rganamiz. Lekin avval bitta narsani aniq tushunib olaylik: Git'da "orqaga" degani har xil joyni anglatadi. Faylni o'zgartirdingizmi, yoki uni add qildingizmi, yoki butunlay commit qildingizmi β har biriga boshqa vosita kerak.
3-bobdagi uch zonani eslang: working (siz tahrirlayotgan fayllar), staging (commitga tayyorlangan o'zgarishlar) va repository (commit qilingan tarix). "Orqaga qaytish" β aslida shu zonalar orasida o'zgarishlarni qaytarish demakdir.
restore β working zonadagi o'zgarishni tashlash¶
Eng birinchi holat β faylni buzdingiz, lekin hali add qilmadingiz. O'zgarish faqat working zonada turibdi. Uni butunlay tashlab, faylni oxirgi commit'dagi holatiga qaytarmoqchisiz.
Avval har doimgidek git status bilan vaziyatni ko'ramiz:
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: index.html
π Git'ning o'zi ko'rsatib turibdi: "discard changes in working directory" uchun git restore <file> ishlat. Git ko'p hollarda keyingi qadamni status chiqishida aytib beradi β o'qishni odat qiling.
Endi o'zgarishni tashlaymiz:
Buyruq hech narsa chop etmaydi (Git'da "jim turish" β "muvaffaqiyat" degani). Faylni qayta ochsangiz β u oxirgi commit'dagi holatiga qaytgan. Kechagi yarim soatlik "tuzatish" yo'qoldi, sayt yana ishlaydi.
β οΈ Ehtiyot bo'ling: git restore qaytarib bo'lmaydigan amal. Working zonadagi o'zgarish hali hech qayerga saqlanmagani uchun, uni tashlasangiz β butunlay yo'qoladi. Git uni tiklab bera olmaydi. Faqat haqiqatan keraksiz o'zgarishni tashlang.
Barcha o'zgartirilgan fayllarni bir vaqtda tashlash uchun:
π‘ Bitta faylni emas, faqat uning bir qismini tashlamoqchimisiz? git restore -p index.html ("patch" rejimi) β Git har bir o'zgarish bo'lagini alohida so'raydi: tashlaymizmi yoki qoldiramizmi.
restore --staged β noto'g'ri add qilinganni unstage qilish¶
Endi ikkinchi holat: git add qildingiz, lekin commit qilishdan oldin o'ylab qoldingiz β bu faylni qo'shmaslik kerak edi. Uni staging'dan chiqarib, faqat working zonada qoldirmoqchisiz (o'zgarish yo'qolmasin, faqat "commitga tayyor" belgisi olib tashlansin).
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: config.txt
π Yana Git'ning o'zi yo'l ko'rsatyapti: "use git restore --staged --staged flagi restorega aytadi: "working zonaga emas, staging zonaga ishla".
Endi git status qilsangiz β config.txt "Changes to be committed" bo'limidan "Changes not staged" bo'limiga ko'chgan. Ya'ni o'zgarish saqlanib qoldi, lekin endi commitga kirmaydi. Bu β unstage (staging'dan chiqarish) deyiladi.
π Farqni yodda saqlang:
- git restore <fayl> β working o'zgarishini tashlaydi (o'zgarish yo'qoladi).
- git restore --staged <fayl> β faqat unstage qiladi (o'zgarish working'da qoladi).
π‘ Eski qo'llanmalarda buni git reset HEAD <fayl> deb o'rgatishadi β u hozir ham ishlaydi, lekin 2026 yilda zamonaviy va aniqroq usul git restore --staged. Git'ning o'zi add qilganingizdan keyin aynan shu buyruqni taklif qiladi.
Agar faylni ham unstage qilib, ham working o'zgarishini tashlamoqchi bo'lsangiz, ikkala flagni birga ishlatasiz:
restore --source β eski versiyani olib kelish¶
restorening yana bir kuchli imkoniyati: faylni nafaqat oxirgi commit'ga, balki istalgan eski commit'dagi holatiga qaytarish. Buning uchun --source flagi:
Bu yerda HEAD~1 β "bitta oldingi commit" degani (5-bobdan tanish). Buyruq index.html faylining o'sha commit'dagi mazmunini olib kelib, working zonangizga qo'yadi. Diqqat: bu commit qilmaydi β faqat working'dagi faylni o'zgartiradi, status'da fayl "modified" bo'lib turadi. Xohlasangiz commit qilasiz, xohlamasangiz yana git restore index.html bilan orqaga qaytarasiz.
π‘ Bu β "faqat bitta faylni o'tmishdan tortib olish" uchun ideal. Masalan, oltita fayldan faqat bittasi kechagi versiyada yaxshiroq edi β butun loyihani orqaga qaytarmasdan, faqat o'sha faylni tiklaysiz.
reset β HEAD'ni orqaga surish¶
restore alohida fayllar bilan ishlaydi. reset esa boshqacha β u butun branch'ni (shox; 7-bobda batafsil) orqaga suradi, ya'ni bir yoki bir nechta commit'ni "olib tashlaydi". Buni tushunish uchun avval HEAD nima ekanligini eslaylik: HEAD β "siz hozir qayerda turibsiz" ko'rsatkichi, odatda oxirgi commit'ga ishora qiladi.
git reset HEAD~1 deganingizda Git'ga aytasiz: "HEAD'ni bitta orqaga sur β go'yo oxirgi commit umuman qilinmagandek". Lekin bu yerda muhim savol tug'iladi: o'sha commit'dagi o'zgarishlar qayerga ketadi? Mana shu savolga resetning uch turi uch xil javob beradi.
| Tur | repository (HEAD) | staging | working |
|---|---|---|---|
--soft |
orqaga suriladi | o'zgarish staged qoladi | tegilmaydi |
--mixed (default) |
orqaga suriladi | bo'shatiladi | tegilmaydi |
--hard |
orqaga suriladi | bo'shatiladi | o'zgarish o'chadi |
E'tibor bering: uchchalasi ham HEAD'ni orqaga suradi. Farq β staging va working zonalarga nima bo'lishida. Yuqoridan pastga qarab, har biri "ko'proq narsani o'chiradi".
reset --soft β commit'ni yechib, o'zgarishni staged qoldirish¶
--soft eng "yumshoq": faqat HEAD'ni orqaga suradi, o'zgarishlaringizni esa staging'da, commitga tayyor holatda qoldiradi.
Go'yo siz commit'ni "yechib oldingiz", lekin ichidagi o'zgarishlar staging'da osilib qoldi. Endi xohlasangiz qaytadan, boshqacha xabar bilan commit qilasiz.
π‘ --soft qachon kerak? Masalan: ikkita commit'ni bittaga birlashtirmoqchisiz, yoki commit xabari yoqmadi, yoki bir nechta mayda commit'ni qayta tartiblamoqchisiz. O'zgarish yo'qolmaydi β faqat commit "qadog'i" yechiladi.
reset --mixed β staging'ni ham bo'shatish (default)¶
--mixed β resetning standart turi. Agar git reset HEAD~1 deb hech qanday flag yozmasangiz, aynan shu ishlaydi. U HEAD'ni orqaga suradi va staging'ni bo'shatadi, lekin working zonadagi fayllaringizga tegmaydi.
Farqni payqadingizmi? --softda o'zgarish "Changes to be committed" (staged) edi, --mixedda esa "Changes not staged" β ya'ni working'da, lekin endi add qilinmagan. O'zgarish baribir yo'qolmaydi, faqat orqaroqqa surildi.
π‘ --mixed qachon kerak? Bir nechta commit'ni butunlay qaytadan, boshqacha bo'lib commit qilmoqchi bo'lganda. Hamma o'zgarish working'da to'planadi β siz ularni xohlagancha qayta add qilib, yangidan bo'lib-bo'lib commit qilasiz.
reset --hard β HAMMASINI o'chirish (XAVFLI)¶
β οΈ Diqqat β bu eng xavfli buyruq. --hard HEAD'ni orqaga suradi, staging'ni bo'shatadi va working zonadagi o'zgarishlaringizni butunlay o'chiradi. Ya'ni siz yozgan, lekin commit qilmagan hamma narsa yo'qoladi.
Buyruqdan keyin git status toza ("nothing to commit"), fayl esa oldingi commit'dagi holatiga to'liq qaytgan. Oxirgi commit ham, undagi o'zgarishlar ham yo'q.
β Hech qachon shoshib --hard ishlatmang. Ayniqsa:
- Commit qilmagan ishingiz bor bo'lsa β u butunlay yo'qoladi.
- Boshqalar bilan ulashgan (push qilingan) commit'ni --hard bilan o'chirsangiz β jamoangiz tarixini buzasiz (buni keyingi bo'limda ko'ramiz).
β
--harddan oldin har doim git status qiling. Saqlanmagan ishingiz yo'qligiga ishonch hosil qiling.
Adashib reset --hard qildimmi? Reflog yordamida tiklang¶
Yaxshi xabar: agar o'chirgan commit'ingiz commit qilingan bo'lsa (working'dagi saqlanmagan o'zgarish emas), uni tiklash mumkin. Git har bir HEAD harakatini maxfiy daftarchada β reflogda yozib boradi.
e49f93b HEAD@{0}: reset: moving to HEAD~1
855e338 HEAD@{1}: commit: C2 muhim
e49f93b HEAD@{2}: commit (initial): C1
Bu yerda HEAD@{1} β resetdan oldingi holat, ya'ni biz o'chirgan "C2 muhim" commit'i. Uni qaytarish:
Tarix tiklandi! π Lekin bunga ortiqcha tayanmang: reflog vaqt o'tishi bilan tozalanadi (odatda 90 kundan keyin), va u faqat lokal β boshqa kompyuterda yo'q. Reflog'ni 16-bobda chuqurroq o'rganamiz. Hozircha esda tuting: "--harddan keyin vahimaga tushmang, avval git reflogga qarang".
revert β eskini bekor qiluvchi yangi commit¶
Endi eng muhim farqqa keldik. reset tarixni o'zgartiradi β commit'ni butunlay olib tashlaydi, go'yo u hech qachon bo'lmagandek. Bu sizning lokal, hali hech kimga ulashilmagan ishingiz uchun zo'r. Lekin commit'ni allaqachon push qilib, jamoangizga ulashib bo'lgan bo'lsangiz-chi?
Mana shu yerda git revert ishga tushadi. U eski commit'ni o'chirmaydi. Aksincha, uning ta'sirini bekor qiluvchi yangi commit yaratadi. Tarix saqlanadi β eski commit ham, uni bekor qilgan yangi commit ham ko'rinib turadi.
Aytaylik, tarix shunday:
"C3: xato ozgarish" β bekor qilmoqchi bo'lgan commit. Uni revert qilamiz:
π Bu buyruq matn muharririni ochib, yangi commit uchun xabar so'raydi (Git "Revert ..." deb tayyor xabar taklif qiladi β odatda shuni qoldirib, saqlab chiqaverasiz). Agar muharrir ochilishini istamasangiz, tayyor xabarni avtomatik qabul qilish uchun:
Natija:
Endi tarixga qaraylik:
b2d6d12 Revert "C3: xato ozgarish"
e2da086 C3: xato ozgarish
fc49aaa C2: yaxshi ozgarish
599ef48 C1: boshlash
Ko'rdingizmi? "C3" commit'i joyida turibdi, lekin uning ustiga "Revert" commit'i qo'shildi. Fayl mazmuni esa "C3" qilinmagandek holatga qaytdi. Hech narsa o'chirilmadi β tarix faqat oldinga o'sdi.
reset vs revert β qaysi biri qachon?¶
Bu β bobning eng muhim qoidasi. Ikki holatni farqlang:
β
Commit hali faqat sizning kompyuteringizda (push qilinmagan) β reset ishlatsangiz bo'ladi. Tarixni o'zgartirish xavfsiz, chunki uni hali hech kim ko'rmagan.
β
Commit allaqachon push qilingan (jamoa ko'rgan) β revert ishlating. Tarixni o'zgartirmang β bekor qiluvchi yangi commit qo'shing.
β Push qilingan commit'ni reset bilan o'chirib, keyin majburan push qilish β bu jamoangiz uchun katta muammo tug'diradi. Boshqalarning tarixida o'sha commit hali bor, sizniki esa endi yo'q β ikkalasi to'qnashadi.
| Holat | Vosita | Nega |
|---|---|---|
| Lokal, push qilinmagan xato commit | git reset |
Tarix shaxsiy, o'zgartirsa bo'ladi |
| Push qilingan, ulashilgan commit | git revert |
Tarix umumiy, faqat qo'shimcha kerak |
| Bir necha commit'ni qayta tartiblash (lokal) | git reset --soft/--mixed |
O'zgarishni saqlab, qaytadan commit |
| Working'dagi saqlanmagan xato | git restore |
HEAD'ga tegmasdan faylni qaytarish |
π‘ Oddiy yodlash qoidasi: "Push qilgan bo'lsam β revert. Push qilmagan bo'lsam β reset".
commit --amend β oxirgi commitni tuzatish¶
Oxirgi keng tarqalgan holat: commit qildingiz, lekin darrov xato sezdingiz. Yoki commit xabarida xatolik bor ("feacher" o'rniga "feature" yozmoqchi edingiz), yoki bitta faylni qo'shishni unutdingiz. Yangi commit yaratish o'rniga, oxirgi commit'ni tuzatish mumkin β git commit --amend.
Faqat xabarni tuzatish:
Unutilgan faylni qo'shish: avval faylni add qiling, keyin amend qiling:
π --no-edit β "xabarni o'zgartirma, eski xabarni qoldir" degani. Faqat fayl qo'shiladi, xabar tegmaydi.
--amenddan keyin git log qilsangiz β yangi commit qo'shilmagan, oxirgi commit'ning o'zi yangilangan. Lekin bitta nozik narsa bor:
β οΈ --amend aslida eski commit'ni yangisi bilan ALMASHTIRADI β commit hash'i o'zgaradi. Demak, bu ham tarixni o'zgartirish. Shuning uchun qoida resetnikidek:
- β
Push qilinmagan oxirgi commit β --amend bemalol.
- β Allaqachon push qilingan commit β --amend qilmang (qilsangiz, push paytida to'qnashuv chiqadi).
π‘ Eslatma: kod misollarida ko'rsatilgan a1b2c3d, e2da086 kabi hash'lar β shunchaki misol. Sizning kompyuteringizda har bir commit'ning hash'i boshqacha bo'ladi, chunki u commit vaqti, muallifi va mazmuniga qarab hisoblanadi. Buyruqlarda HEAD'ni nishonga olganda HEAD, HEAD~1 kabi nisbiy nomlardan foydalanish β hash'ni qo'lda ko'chirishdan ko'ra ishonchliroq.
Hammasini bir joyda: qaysi vosita qaysi muammoga?¶
| Muammo | Yechim |
|---|---|
Faylni buzdim, hali add qilmadim |
git restore <fayl> |
Noto'g'ri add qildim (commit qilmadim) |
git restore --staged <fayl> |
| Eski versiyadagi bitta faylni tortib olmoqchiman | git restore --source=<commit> <fayl> |
| Oxirgi commit'ni yechib, o'zgarishni saqlamoqchiman | git reset --soft HEAD~1 |
| Bir necha commit'ni qaytadan bo'lib commit qilmoqchiman | git reset --mixed HEAD~1 |
| Lokal commit'ni butunlay o'chirmoqchiman (ehtiyot!) | git reset --hard HEAD~1 |
--hard qildim, tiklamoqchiman |
git reflog + git reset --hard HEAD@{n} |
| Push qilingan commit'ni bekor qilmoqchiman | git revert <commit> |
| Oxirgi commit xabari/faylini tuzatmoqchiman | git commit --amend |
π Eng muhim umumiy qoida: "Push qilingunimcha tarix mening shaxsiy daftarim β istaganimcha o'chiraman (reset, amend). Push qildimmi β tarix umumiy, faqat qo'shaman (revert)".
6-bob mashqlari¶
Quyidagi mashqlarni alohida sinov papkasida bajaring β loyihangizning haqiqiy .git katalogiga tegmang. Avval biror joyda yangi papka yarating, unda git init qiling va sinov fayllari bilan ishlang. Har bir mashqdan oldin va keyin git status hamda git log --oneline qilib, holat qanday o'zgarganini kuzating.
- Yangi sinov papkasi yarating,
git initqiling,init.defaultBranch mainekanini tekshiring vafeature.txtfaylida bitta commit yarating. feature.txtni tahrirlang (haliaddqilmang),git statusbilan "Changes not staged" holatini ko'ring, so'nggit restore feature.txtbilan o'zgarishni tashlang va fayl oldingi holatga qaytganini tasdiqlang.feature.txtni tahrirlabgit addqiling,git statusda "Changes to be committed" holatini ko'ring, so'nggit restore --staged feature.txtbilan uni unstage qiling. O'zgarish working'da qolganini tekshiring.- Faylni tahrirlang va
git addqiling. Endi bitta buyruq bilan ham unstage qiling, ham working o'zgarishini tashlang (git restore --staged --worktree). Natijada status butunlay toza bo'lishi kerak. - Uchta fayl yarating (
a.txt,b.txt,c.txt), uchchalasini ham tahrirlang.git restore .bilan hammasining o'zgarishini bir vaqtda tashlang. feature.txtda uchta ketma-ket commit yarating (har birida bitta yangi qator).git log --onelinebilan tarixni ko'ring va hash'larni eslab qoling.git restore --source=HEAD~2 feature.txtbilan faylning ikki commit oldingi holatini working zonangizga olib keling. Commit o'zgarmaganini (git logo'sha) va faylning o'zgarganini (git status"modified") tasdiqlang.- Yangi sinov papkasida ikkita commit yarating.
git reset --soft HEAD~1qiling.git statusda o'zgarishning "Changes to be committed" (staged) bo'lib qolganini tekshiring. - Xuddi shu holatni qaytadan tayyorlang (ikkita commit) va bu safar
git reset --mixed HEAD~1qiling. Endi o'zgarish "Changes not staged" (working) bo'lib qolganini, ya'ni--softdan farqini ko'ring. git reset HEAD~1(flagsiz) qilib, uning aynan--mixedbilan bir xil natija berishiga ishonch hosil qiling.- Yana ikkita commit tayyorlang.
git reset --hard HEAD~1qiling vagit statustoza, fayl esa oldingi commit holatiga qaytganini ko'ring. Bu safar o'zgarish butunlay yo'qolganiga e'tibor bering. - 11-mashqdan so'ng darrov
git reflogqiling, o'chirgan commit'niHEAD@{1}da toping vagit reset --hard HEAD@{1}bilan uni tiklang. Tarix qaytib kelganini tasdiqlang. - Working zonangizda commit qilinmagan o'zgarish yarating (faylga yangi qator yozing,
addqilmang), so'nggit reset --hardqiling. Bu o'zgarishni reflog tiklay olmasligini ko'ring β nega ekanini o'ylab toping (chiqarib qo'yilgan, lekin commit qilinmagan ish saqlanmaydi). - Uchta commit'li tarix yarating. Oxirgi commit'ni
git revert HEADbilan bekor qiling (--no-editishlatishingiz mumkin).git log --onelinebilan eski commit JOYIDA turganini va ustiga "Revert" commit'i qo'shilganini tasdiqlang. - 14-mashqdan keyin fayl mazmunini ochib ko'ring: revert qilingan commit kiritgan o'zgarish bekor qilinganini, lekin tarix uzunligi qisqarmaganini tekshiring.
- O'rtadagi commit'ni revert qiling (oxirgini emas):
git revert HEAD~1. Natijani kuzating va konflikt chiqsa-chiqmasligini qayd eting. - Bitta commit yarating, ataylab xato xabar bilan (masalan "Qoshildi: feacher").
git commit --amend -m "Qoshildi: feature"bilan xabarni tuzating.git logbilan yangi commit qo'shilmaganini, faqat xabar o'zgarganini tasdiqlang. - Bitta commit yarating, keyin bir faylni qo'shishni "unutgan" bo'ling. O'sha faylni
addqilib,git commit --amend --no-editbilan oxirgi commit'ga qo'shing.git show --stat HEADbilan ikkala fayl ham bitta commit'da ekanini tekshiring. --amenddan oldin va keyingit log --onelinechiqishidagi commit hash'ini solishtiring: hash o'zgarganini ko'ring va nega bu "tarixni o'zgartirish" hisoblanishini o'z so'zlaringiz bilan izohlang.- Yakuniy mashq: bitta papkada quyidagi ssenariyni o'ynang β (a) faylni buzing va
restorebilan qaytaring; (b) noto'g'riaddqilibrestore --stagedbilan unstage qiling; (c) xato commit qilib, u push qilinmagani uchunresetbilan o'chiring; (d) "go'yo push qilingan" boshqa commit'ni esarevertbilan bekor qiling. Har bosqichda qaysi vositani nega tanlaganingizni bir jumlada yozib boring.