git rebase — nima, merge dan farqi, qachon ishlatiladi

~20 daq · Git · Branch va Merge

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:

  1. feature/savat dagi commitlarni (A, B, C) vaqtincha "olib qo'ydi"
  2. Branch ni main ning oxiriga ko'chirdi
  3. 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 main ni) 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, develop va 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 --ours va --theirs teskari 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 commitlarini main ning oxiriga qayta qo'llash
  • Natija — to'g'ri chiziqli tarix; keyin main ga 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 / drop
  • commit --fixup + rebase -i --autosquash

Keyingi dars

18-dars: git stash — o'zgarishlarni vaqtincha saqlash, list, pop, drop