git rebase — nima, merge dan farqi, qachon ishlatiladi
Muammodan boshlaylik
Faol loyihaning git log --graph i:
* e5f6a7b Merge branch 'main' into feature/savat
|\
| * d4e5f6a Header yangilandi
* | c3d4e5f Merge branch 'main' into feature/savat
|\ \
| |/
| * b2c3d4e Footer tuzatildi
* | a1b2c3d Savat: miqdor tanlash
|/
* 9a8b7c6 Merge branch 'feature/login'
Har safar main dan yangiliklarni olish — yangi merge commit. Tarix — chalkash "temir yo'l xaritasi". Haqiqiy ish (savat) shovqin ichida yo'qolib qoladi.
Rebase — branch ni boshqa asosga "ko'chirib", tarixni to'g'ri chiziq qiladi.
Rebase nima qiladi
Boshlang'ich holat:
main
↓
●────●────●────●────● (main da 2 yangi commit)
\
A────B────C feature/savat
↑
git switch feature/savat
git rebase main
Successfully rebased and updated refs/heads/feature/savat.
Natija:
main
↓
●────●────●────●────●
\
A'───B'───C' feature/savat
↑
Git:
feature/savatdagi commitlarni (A, B, C) vaqtincha "olib qo'ydi"- Branch ni
mainning oxiriga ko'chirdi - Commitlarni birma-bir qayta qo'lladi — A', B', C'
Endi branch go'yo main ning eng yangi holatidan boshlangandek. Merge commit yo'q. main ga qo'shish esa — oddiy fast-forward (15-dars).
[!INFO] A' va A — turli commitlar: mazmuni bir xil, lekin ota-onasi va hash i boshqa. Rebase tarixni qayta yozadi — bu uning kuchi ham, xavfi ham.
Merge va rebase — taqqoslash
MERGE: REBASE:
●──●──●──●──◆ main ●──●──●──●──A'──B'──C' main
\ / (fast-forward)
A──B──C
| Merge | Rebase | |
|---|---|---|
| Tarix | Haqiqiy — qanday bo'lgan bo'lsa | Toza, to'g'ri chiziq |
| Qo'shimcha commit | Merge commit | Yo'q |
| Mavjud commitlar | O'zgarmaydi | Qayta yoziladi (yangi hash) |
| Conflict | Bir marta, oxirida | Har bir commit da alohida bo'lishi mumkin |
| Ommaviy branch da | ✅ Xavfsiz | ⚠️ Xavfli |
Oltin qoida
[!WARNING] Boshqalar ishlatayotgan commitlarni hech qachon rebase qilmang. Push qilingan va hamkasblaringiz o'z ishini ustiga qurgan branch ni (ayniqsa
mainni) rebase qilsangiz — ularning tarixi va sizniki ajralib ketadi, va ular sizning commitlaringizni ikki nusxada oladi. Natija — jamoa uchun bosh og'rig'i.
Xavfsiz:
- ✅ Hali push qilinmagan lokal commitlarni
- ✅ Faqat siz ishlayotgan shaxsiy feature branch ni (push qilingan bo'lsa ham — pastga qarang)
Xavfli:
- ❌
main,developva boshqa umumiy branch lar - ❌ Hamkasb ham commit qilayotgan branch
Rebase dan keyin push
Feature branch ni allaqachon push qilgan bo'lsangiz, rebase dan keyin oddiy git push rad etiladi (tarixlar mos emas):
git push --force-with-lease
--force-with-lease — xavfsiz "majburiy push": agar GitHub dagi branch siz oxirgi marta ko'rgandan keyin boshqa birov tomonidan o'zgartirilgan bo'lsa — rad etadi. Oddiy --force esa ularning ishini jimgina o'chiradi. Hech qachon --force emas — har doim --force-with-lease.
Rebase paytidagi conflict
Rebase commitlarni birma-bir qo'llaydi — conflict har qanday qadamda chiqishi mumkin:
CONFLICT (content): Merge conflict in src/savat.js
error: could not apply b2c3d4e... Savat: miqdor tanlash
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
Hal qilish (16-dars bilan bir xil):
# 1. Faylni tahrirlang, belgilarni olib tashlang
git add src/savat.js
git rebase --continue # keyingi commit ga o'tish (commit QILMANG!)
Boshqa variantlar:
git rebase --skip # bu commit ni tashlab yuborish
git rebase --abort # hammasini bekor qilish — rebase dan oldingi holatga
[!INFO] Rebase paytida
--oursva--theirsteskari ma'noga ega:ours— siz ustiga qo'yayotgan asos (main),theirs— sizning qayta qo'llanayotgan commitlaringiz. Chalkash, shuning uchun VS Code tugmalaridan foydalaning va natijani diqqat bilan o'qing.
Interaktiv rebase — tarixni tozalash
Rebase ning eng kuchli shakli — commitlarni tahrirlash. PR yuborishdan oldin lokal tarixingiz:
f6a7b8c fix typo
e5f6a7b WIP
d4e5f6a Savat: miqdor tanlash
c3d4e5f oops, console.log o'chirildi
b2c3d4e Savat sahifasi
Buni ko'rib chiquvchiga yuborish — noqulay. Tozalaymiz:
git rebase -i HEAD~5
Muharrir ochiladi (eng eskisi tepada):
pick b2c3d4e Savat sahifasi
pick c3d4e5f oops, console.log o'chirildi
pick d4e5f6a Savat: miqdor tanlash
pick e5f6a7b WIP
pick f6a7b8c fix typo
# Commands:
# p, pick = commit ni o'zgarishsiz qoldirish
# r, reword = xabarini o'zgartirish
# s, squash = oldingi commit bilan birlashtirish (xabarlarni ham)
# f, fixup = oldingi bilan birlashtirish, xabarini tashlab
# d, drop = commit ni o'chirish
O'zgartiramiz:
pick b2c3d4e Savat sahifasi
fixup c3d4e5f oops, console.log o'chirildi
pick d4e5f6a Savat: miqdor tanlash
fixup e5f6a7b WIP
fixup f6a7b8c fix typo
Saqlab yoping. Natija:
a1b2c3d Savat: miqdor tanlash
9f8e7d6 Savat sahifasi
Ikki toza, mantiqiy commit. Qatorlar tartibini o'zgartirib, commitlar tartibini ham o'zgartirish mumkin.
fixup commit lar — avtomatlashtirilgan
Eski commit da xato topdingiz:
git add src/savat.js
git commit --fixup b2c3d4e # "fixup! Savat sahifasi" commit i
git rebase -i --autosquash main # Git uni avtomatik to'g'ri joyga qo'yadi
Qachon nima ishlatiladi
| Vaziyat | Tavsiya |
|---|---|
main dagi yangiliklarni o'z feature branch ingizga olish |
git rebase main (yoki merge main — jamoa kelishuviga ko'ra) |
| PR yuborishdan oldin lokal commitlarni tozalash | git rebase -i |
git pull da keraksiz merge commitlar |
git pull --rebase (22-dars) |
Feature ni main ga qo'shish |
Merge (yoki GitHub ning "Rebase and merge" / "Squash") |
| Umumiy branch | Faqat merge |
git config --global pull.rebase true # git pull har doim rebase bilan
Nima uchun shunday?
Rebase tarixni "yolg'on" qiladi — haqiqatda branch eski main dan boshlangan edi. Nima uchun bunday qilish kerak?
Chunki tarixning maqsadi — o'qilish, kundalikdagi har bir qadamni yozish emas. Kelajakdagi o'quvchiga "Otabek seshanba kuni 14:00 da main ni o'z branch iga qo'shgan" degan ma'lumot kerak emas — unga "savat funksiyasi shu 2 ta mantiqiy o'zgarishdan iborat" kerak. Rebase va interaktiv rebase — bu kitob qoralamasini nashrdan oldin tahrirlash kabi: yozish jarayoni tartibsiz, lekin nashr qilingan matn toza va mantiqiy. Muhim chegara: tahrirlash nashrdan oldin (push dan va boshqalar ishlatishidan oldin) qilinadi. Nashr qilingan kitobni qayta yozish — o'quvchilarni chalg'itadi.
Xulosa
Eslab qoling:
git rebase main— joriy branch commitlarinimainning oxiriga qayta qo'llash- Natija — to'g'ri chiziqli tarix; keyin
mainga fast-forward - Commitlar qayta yoziladi (yangi hash)
- Oltin qoida: boshqalar ishlatayotgan commitlarni rebase qilmang
- Rebase dan keyin push —
--force-with-lease(hech qachon--force) - Conflict: tahrirlash →
git add→git rebase --continue;--abort— bekor git rebase -i HEAD~N— pick / reword / squash / fixup / dropcommit --fixup+rebase -i --autosquash
Keyingi dars
18-dars: git stash — o'zgarishlarni vaqtincha saqlash, list, pop, drop