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

Git rebase: tarixni chiziqlash va oltin qoida

Qisqacha: git rebase main joriy branch'dagi commitlarni olib, ularni main ning eng oxirgi commiti ustiga qaytadan qo'yadi. Natijada tarix to'g'ri chiziq bo'ladi va keyingi merge fast-forward bilan o'tadi. Lekin rebase yangi commitlar yaratadi — SHA'lar o'zgaradi. Shuning uchun oltin qoida: boshqalar ham ishlatayotgan (GitHub'ga yuborilgan, umumiy) branch'ni hech qachon rebase qilmang.

Bu darsda

  • Rebase commitlarni qanday "ko'chirishini" va nega SHA'lar o'zgarishini tushuntirasiz.
  • git rebase main bilan branch'ingizni yangilab, fast-forward merge qilasiz.
  • Rebase paytidagi conflict'ni --continue, --abort va --skip bilan boshqarasiz.
  • Oltin qoidani va uning sababini aniq ayta olasiz.
  • Merge va rebase'ni solishtirib, qaysi vaziyatda qaysi biri qulayligini tanlaysiz.

Oldin bilishingiz kerak: Merge: fast-forward va uch tomonlama birlashtirish, Conflictlarni yechish amaliyoti, HEAD, refs va detached HEAD.

1. Nega bu kerak?

«Bahor» tarixiga qarang. Oxirgi uch darsda uch marta merge qildik va tarixda uchta "cho'ntak" paydo bo'ldi. Kichik loyihada bu muammo emas. Lekin o'nta dasturchi har kuni ishlaydigan loyihada git log --graph rel-yo'llar tugunidek chalkash bo'lib ketadi. "Bu o'zgarish qachon kirgan?" degan savolga javob topish qiyinlashadi.

Bundan tashqari, merge commitlarning ko'pi hech qanday ma'lumot bermaydi. "Merge branch 'main' into feature/..." — bu faqat "men yangiliklarni oldim" degani. Tarixda shovqin ko'payadi.

Git'da ikkinchi yo'l bor — rebase (asosni almashtirish). G'ishtli devorni tasavvur qiling. Siz o'z qatoringizni devorning eski joyiga qo'yishni boshlagan edingiz, bu orada boshqalar devorni ikki qator ko'tarib qo'ydi. Rebase — g'ishtlaringizni olib, devorning yangi, eng yuqori qatoriga qayta terish. Natijada devor tekis, bitta chiziq.

Merge darsida --ff-only xatosi ham shu yo'lni maslahat bergan edi: git rebase. Bugun uni ochamiz.

2. Birinchi rebase

2.1 Vaziyat

Menyuga ichimliklar bo'limini qo'shish uchun branch ochamiz va ikki commit qilamiz:

bash
cd ~/kurs/bahor
git switch -c feature/ichimliklar
echo '<h2>Ichimliklar</h2>' >> menyu/index.html
git commit -am "Menyu: ichimliklar bo'limini qo'sh"
echo "<p>Ko'k choy — 5 000 so'm</p>" >> menyu/index.html
git commit -am "Menyu: ko'k choy qo'sh"
text
Switched to a new branch 'feature/ichimliklar'
[feature/ichimliklar df4ac38] Menyu: ichimliklar bo'limini qo'sh
 1 file changed, 1 insertion(+)
[feature/ichimliklar afcf200] Menyu: ko'k choy qo'sh
 1 file changed, 1 insertion(+)

Shu orada main da bosh sahifaga ish vaqti yozildi (git switch main, keyin index.html ga qator va commit):

text
[main 37c92ec] Bosh sahifa: ish vaqtini qo'sh
 1 file changed, 1 insertion(+)

Tarix ayrildi:

bash
git log --oneline --graph --all -5
text
* 37c92ec (HEAD -> main) Bosh sahifa: ish vaqtini qo'sh
| * afcf200 (feature/ichimliklar) Menyu: ko'k choy qo'sh
| * df4ac38 Menyu: ichimliklar bo'limini qo'sh
|/  
*   7658a99 Merge branch 'fix/lagmon-narxi'
|\  
| * 6eb3409 Menyu: lag'mon narxini 30 000 qil

-5 — faqat oxirgi beshta commit. Pastdagi |\ — o'tgan darsdagi merge'ning boshlanishi, u bizga hozir kerak emas.

gitGraph
  commit id: "7658a99 merge"
  branch feature/ichimliklar
  commit id: "df4ac38 bo'lim"
  commit id: "afcf200 choy"
  checkout main
  commit id: "37c92ec ish vaqti"

Nimaga qarang: feature/ichimliklar 7658a99 dan o'sgan — bu uning asosi (base). main esa o'shandan beri bir qadam yurgan. Oddiy git merge qilsak, yana bitta merge commit va yana bitta cho'ntak paydo bo'ladi.

2.2 git rebase main

Rebase'ni ko'chiriladigan branch'da turib qilamiz — ya'ni o'z branch'imizda:

bash
git switch feature/ichimliklar
git rebase main
text
Switched to branch 'feature/ichimliklar'
Successfully rebased and updated refs/heads/feature/ichimliklar.

Tarjimasi: "Muvaffaqiyatli rebase qilindi va refs/heads/feature/ichimliklar yangilandi". Terminalda bir lahza Rebasing (1/2), Rebasing (2/2) yozuvlari ham chaqnab o'tadi — Git har commitni navbat bilan ko'chirayotganini ko'rsatadi, keyin bu yozuv ustidan yangisi yoziladi.

Tarixga qaraymiz:

bash
git log --oneline --graph --all -5
text
* e666b2d (HEAD -> feature/ichimliklar) Menyu: ko'k choy qo'sh
* 6761532 Menyu: ichimliklar bo'limini qo'sh
* 37c92ec (main) Bosh sahifa: ish vaqtini qo'sh
*   7658a99 Merge branch 'fix/lagmon-narxi'
|\  
| * 6eb3409 Menyu: lag'mon narxini 30 000 qil

Ayrilish yo'qoldi. Ikkala commitimiz endi 37c92ec ustida turibdi — go'yo biz ishni ish vaqti yozilgandan keyin boshlagandek.

gitGraph
  commit id: "7658a99 merge"
  commit id: "37c92ec ish vaqti"
  branch feature/ichimliklar
  commit id: "6761532 bo'lim"
  commit id: "e666b2d choy"

Nimaga qarang: branch'ning asosi 7658a99 dan 37c92ec ga ko'chdi. Nomi "rebase" — "re-base", asosni qayta belgilash — shundan.

2.3 SHA'lar o'zgardi!

Diqqat bilan solishtiring:

Commit Rebase'dan oldin Rebase'dan keyin
Ichimliklar bo'limi df4ac38 6761532
Ko'k choy afcf200 e666b2d

Xabarlar, fayldagi o'zgarishlar — bir xil. SHA'lar esa boshqa. Nega?

Git ichkaridan darsini eslang: commit SHA'si commitning butun mazmunidan hisoblanadi — daraxt, muallif, sana, xabar va ota commit. Rebase'dan keyin birinchi commitning otasi boshqa (7658a99 emas, 37c92ec). Demak SHA ham boshqa. Ikkinchisining otasi esa birinchisi — u ham o'zgardi.

Ya'ni rebase commitlarni "ko'chirmaydi". U yangi commitlar yaratadi: eskilarining nusxasini yangi asos ustiga. Eski commitlar esa hech qaerga ketmaydi — ularga shunchaki endi hech bir branch ishora qilmaydi. Git rebase'dan oldingi joyni ORIG_HEAD da eslab qoladi (HEAD va refs darsidan):

bash
git log --oneline -1 ORIG_HEAD
text
afcf200 Menyu: ko'k choy qo'sh

Eski uch shu yerda. Rebase natijasi yoqmasa, git reset --hard ORIG_HEAD hammasini qaytaradi (reset darsidan). Bu "orqaga yo'l" haqida ko'proq — Reflog darsida.

2.4 Endi merge — fast-forward

bash
git switch main
git merge feature/ichimliklar
text
Switched to branch 'main'
Updating 37c92ec..e666b2d
Fast-forward
 menyu/index.html | 2 ++
 1 file changed, 2 insertions(+)

Merge commit yo'q! main shunchaki oldinga surildi, chunki rebase'dan keyin feature/ichimliklar uning to'g'ridan-to'g'ri davomi edi.

bash
git log --oneline --graph -5
git branch -d feature/ichimliklar
text
* e666b2d (HEAD -> main, feature/ichimliklar) Menyu: ko'k choy qo'sh
* 6761532 Menyu: ichimliklar bo'limini qo'sh
* 37c92ec Bosh sahifa: ish vaqtini qo'sh
*   7658a99 Merge branch 'fix/lagmon-narxi'
|\  
| * 6eb3409 Menyu: lag'mon narxini 30 000 qil
Deleted branch feature/ichimliklar (was e666b2d).

Mana "rebase + fast-forward" usuli: tarix tekis chiziq, har commit o'z joyida.

Tekshirib ko'ring: Rebase'dan keyin df4ac38 commiti o'chib ketdimi?

Javob

Yo'q. U hali ham .git ichida bor — shuning uchun ORIG_HEAD orqali ko'ra oldik. Faqat endi hech bir branch unga ishora qilmaydi. Bunday "yetim" commitlarni Git bir necha haftadan keyin tozalab yuboradi, lekin ungacha ularni qaytarish mumkin.

3. Rebase ichkaridan

Rebase uch qadamda ishlaydi:

  1. Git joriy branch va main ning umumiy ajdodini topadi (merge base).
  2. Branch'dagi ajdoddan keyingi commitlarni vaqtincha chetga oladi va branch'ni main uchiga qo'yadi.
  3. Chetga olingan commitlarni birma-bir, tartib bilan qaytadan qo'llaydi — har biri yangi commit bo'ladi.
flowchart LR
  A["Umumiy ajdodni<br/>topish"] --> B["Commitlarni<br/>chetga olish"]
  B --> C["main uchiga<br/>o'tish"]
  C --> D["1-commitni<br/>qo'llash"]
  D --> E["2-commitni<br/>qo'llash"]
  E --> F["Branch nomini<br/>surish"]
  D -. conflict .-> G["To'xtab,<br/>sizni kutadi"]

Nimaga qarang: commitlar bitta-bitta qo'llanadi. Shuning uchun rebase'dagi conflict bitta commit ustida chiqadi — va bir rebase davomida bir necha marta chiqishi mumkin. Merge'da esa hamma conflict bir marta, bir joyda chiqadi.

4. Rebase paytida conflict

4.1 Conflict chiqadi

Somsa haqida ikki ish bir qatorga tegdi. feature/somsa-turlari da somsa turlari yozildi va izoh qo'shildi:

text
[feature/somsa-turlari 9d5596d] Menyu: somsa turlarini qo'sh
 1 file changed, 1 insertion(+), 1 deletion(-)
[feature/somsa-turlari 4ffb780] Menyu: qovoqli somsa izohini qo'sh
 1 file changed, 1 insertion(+)

main da esa shu orada somsa narxi 9 000 bo'ldi (a73d1c1). Branch'da turib rebase qilamiz:

bash
git rebase main
text
Auto-merging menyu/index.html
CONFLICT (content): Merge conflict in menyu/index.html
error: could not apply 9d5596d... Menyu: somsa turlarini qo'sh
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Recorded preimage for 'menyu/index.html'
Could not apply 9d5596d... # Menyu: somsa turlarini qo'sh

Tarjimasi: "9d5596d ni qo'llab bo'lmadi. Hamma ziddiyatlarni qo'lda yeching, git add/rm bilan belgilang, keyin git rebase --continue ni ishga tushiring. Buning o'rniga bu commitni o'tkazib yuborish mumkin: git rebase --skip. Rebase'dan oldingi holatga qaytish uchun: git rebase --abort". Recorded preimage — Conflictlar darsida yoqqan rerere ishi.

Git birinchi commit ustida to'xtadi. Ikkinchisi hali navbatda.

4.2 Holatni o'qish

bash
git status
text
interactive rebase in progress; onto a73d1c1
Last command done (1 command done):
   pick 9d5596d # Menyu: somsa turlarini qo'sh
Next command to do (1 remaining command):
   pick 4ffb780 # Menyu: qovoqli somsa izohini qo'sh
  (use "git rebase --edit-todo" to view and edit)
You are currently rebasing branch 'feature/somsa-turlari' on 'a73d1c1'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   menyu/index.html

no changes added to commit (use "git add" and/or "git commit -a")

Yuqori qismi yangi: "a73d1c1 ustiga rebase ketmoqda. Bajarilgan buyruq: pick 9d5596d. Keyingisi: pick 4ffb780". pick — "shu commitni ol va qo'lla". Bu ro'yxat bilan keyingi darsda o'zingiz ishlaysiz. Hozir muhimi: bir commit bajarildi (conflict bilan), bittasi kutyapti.

4.3 Markerlar — va teskari "biz"

bash
cat menyu/index.html
text
<h1>Menyu</h1>
<p>Osh — 38 000 so'm (qazi bilan)</p>
<p>Lag'mon — 30 000 so'm (qo'l lag'mon)</p>
<<<<<<< HEAD
<p>Somsa — 9 000 so'm</p>
||||||| parent of 9d5596d (Menyu: somsa turlarini qo'sh)
<p>Somsa — 8 000 so'm</p>
=======
<p>Somsa — 8 000 so'm (go'shtli, qovoqli)</p>
>>>>>>> 9d5596d (Menyu: somsa turlarini qo'sh)
<p>Shashlik — 15 000 so'm</p>
<h2>Ichimliklar</h2>
<p>Ko'k choy — 5 000 so'm</p>

Diqqat! Bu yerda HEAD — main ning versiyasi (9 000), sizning commitingiz esa pastda, >>>>>>> 9d5596d. Merge'dagiga teskari.

Sababi «Rebase ichkaridan» bo'limida: rebase paytida Git avval main uchiga o'tadi, keyin sizning commitlaringizni unga qo'llaydi. Demak HEAD — qurilayotgan yangi asos, "kelayotgan" esa sizning commitingiz. Shu sababli rebase'da --ours — main tomoni, --theirs — sizning commitingiz. Conflictlar darsidagi ogohlantirish shu edi. Chalkashmaslik uchun so'zlarga emas, markerdagi nom va SHA'ga qarang.

||||||| ostida asl qator: parent of 9d5596d — "commitimizning otasidagi holat".

4.4 --abort — boshiga qaytish

Avval xavfsiz chiqish yo'lini sinaymiz:

bash
git rebase --abort
git log --oneline --graph --all -4
text
* a73d1c1 (main) Menyu: somsa narxini 9 000 qil
| * 4ffb780 (HEAD -> feature/somsa-turlari) Menyu: qovoqli somsa izohini qo'sh
| * 9d5596d Menyu: somsa turlarini qo'sh
|/  
* e666b2d Menyu: ko'k choy qo'sh

Hammasi rebase'dan oldingidek: eski SHA'lar, ayrilgan tarix. --abort rebase'ning istalgan joyida ishlaydi.

4.5 Yechish va --continue

Qaytadan git rebase main — yana o'sha conflict. Bu safar yechamiz. Ikkala o'zgarish kerak: yangi narx va turlar. Fayldagi somsa qatorini shunday qoldiramiz:

text
<p>Somsa — 9 000 so'm (go'shtli, qovoqli)</p>

Markerlarni o'chirib, faylni saqlaymiz. Keyin — merge'dagidan farqli — git commit emas, git rebase --continue:

bash
git add menyu/index.html
git rebase --continue

VS Code'da commit xabari ochiladi (Menyu: somsa turlarini qo'sh) — o'zgartirmay yopamiz:

text
Recorded resolution for 'menyu/index.html'.
[detached HEAD d6cee25] Menyu: somsa turlarini qo'sh
 1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/feature/somsa-turlari.

[detached HEAD d6cee25] — rebase davomida Git branch'da emas, to'g'ridan-to'g'ri commitlarda ishlaydi (detached HEAD). Oxirida branch nomi yangi uchga ko'chiriladi. Ikkinchi commit conflictsiz qo'llandi.

bash
git log --oneline --graph --all -4
text
* 95b5e40 (HEAD -> feature/somsa-turlari) Menyu: qovoqli somsa izohini qo'sh
* d6cee25 Menyu: somsa turlarini qo'sh
* a73d1c1 (main) Menyu: somsa narxini 9 000 qil
* e666b2d Menyu: ko'k choy qo'sh

Endi git switch main va git merge feature/somsa-turlari — fast-forward (Updating a73d1c1..95b5e40).

Diqqat: Rebase paytida git commit yozmang. Conflictni yechgach — git add va git rebase --continue. Git commitni o'zi yaratadi va keyingisiga o'tadi.

Tekshirib ko'ring: Rebase paytidagi conflict'da <<<<<<< HEAD ostidagi qator kimniki — sizning branch'ingiznikimi yoki main nikimi?

Javob

main niki. Rebase main uchida turib sizning commitlaringizni birma-bir qo'llaydi, shuning uchun HEAD — yangi asos. Sizning commitingiz >>>>>>> markeri yonida, SHA va xabari bilan ko'rsatiladi.

5. --skip va avtomatik tashlab ketish

5.1 Commit allaqachon main da bo'lsa

fix/choy-narxi branch'ida ikki commit bor: choy narxi 6 000 va non narxi. Shu orada kimdir main da aynan o'sha choy o'zgarishini alohida commit qildi ("Menyu: choy narxini yangila"). Rebase:

bash
git rebase main
text
warning: skipped previously applied commit a17aaa9
hint: use --reapply-cherry-picks to include skipped commits
hint: Disable this message with "git config set advice.skippedCherryPicks false"
Successfully rebased and updated refs/heads/fix/choy-narxi.

Tarjimasi: "ogohlantirish: oldin qo'llangan a17aaa9 commiti o'tkazib yuborildi". Git branch'dagi choy commitining o'zgarishi main da bor ekanini sezdi va uni takrorlamadi. Natijada branch'da faqat non narxi qoldi:

text
* 0be6fbb (HEAD -> fix/choy-narxi) Menyu: non narxini qo'sh
* 100e51b (main) Menyu: choy narxini yangila

Xabarlar boshqa bo'lsa ham, Git o'zgarishning mazmunini solishtiradi.

5.2 --skip — o'zingiz tashlab ketish

Ba'zan conflict chiqadi, siz esa tushunasiz: bu commit endi kerak emas. Masalan, branch'da non narxi 5 000, main da esa allaqachon 4 500 qilingan — va to'g'risi main dagisi. Conflict'da:

bash
git rebase --skip
text
Successfully rebased and updated refs/heads/fix/non-narxi.

Conflictli commit butunlay tashlandi — go'yo u hech qachon bo'lmagandek. Bizda branch'da boshqa commit yo'q edi, shuning uchun branch main bilan tenglashdi. --skip — o'sha commitdagi hamma o'zgarishdan voz kechish, shuning uchun uni o'ylab ishlating.

6. Oltin qoida

6.1 Qoida

Diqqat: Boshqalar ham ishlatayotgan branch'ni rebase qilmang. Ya'ni GitHub'ga yuborilgan va kimdir o'ziga olgan branch'ni — ayniqsa main ni — hech qachon.

6.2 Nega?

«SHA'lar o'zgardi!» bo'limini eslang: rebase eski commitlarni tashlab, yangilarini yaratadi. Faqat sizning kompyuteringizda bo'lsa — hech kim zarar ko'rmaydi.

Endi tasavvur qiling: feature/ichimliklar GitHub'da turibdi va Rustam aka uni o'z kompyuteriga olib, ustiga commit qo'shdi. Siz esa branch'ni rebase qildingiz. Sizda — yangi 6761532, e666b2d. Rustam akada — eski df4ac38, afcf200 va uning commiti.

flowchart TB
  subgraph S["Sizda (rebase'dan keyin)"]
    A1["37c92ec"] --> A2["6761532"] --> A3["e666b2d"]
  end
  subgraph R["Rustam akada"]
    B1["7658a99"] --> B2["df4ac38"] --> B3["afcf200"] --> B4["Rustamning commiti"]
  end

Nimaga qarang: bir xil ish, ikki xil tarix. Git uchun df4ac38 va 6761532 — butunlay boshqa commitlar. Ikki tarix birlashganda o'sha o'zgarishlar ikki nusxada paydo bo'ladi, conflictlar ko'payadi, jamoa soatlab chalkashlikni tozalaydi.

Buni bitta kompyuterda ham ko'rsa bo'ladi. sinov-git/oltin repoda feature/salatlar branch'ini "Rustam oldi" — biz uning nusxasini rustam nomli branch qilib qo'ydik va ustiga commit qo'shdik. Keyin feature/salatlar ni main ustiga rebase qildik, ikkalasini main ga birlashtirdik:

bash
git log --oneline
text
22e1e7a (HEAD -> main) Merge branch 'rustam'
306bb27 (feature/salatlar) Menyu: olivye qo'sh
69e8af9 Menyu: achchiq-chuchuk qo'sh
7d06ace Manzil: faylni qo'sh
8df60e3 (rustam) Narxlar: faylni qo'sh
d04313d Menyu: olivye qo'sh
f335f5d Menyu: achchiq-chuchuk qo'sh
ae14b80 Menyu: faylni yarat

"Olivye" va "achchiq-chuchuk" commitlari tarixda ikki marta turibdi: yangi SHA bilan (306bb27, 69e8af9) va eski SHA bilan (d04313d, f335f5d). Fayl mazmuni to'g'ri chiqdi, lekin tarix chalkashdi. Haqiqiy loyihada bunday dublikatlar conflictlarga va "bu commit qaysi?" degan savollarga olib keladi.

GitHub'ga yuborish va boshqalardan olish (Remote darsi) hali o'tilmagan. Hozircha oddiy qoida yetadi: rebase — faqat o'zingizning, hali hech kimga bermagan commitlaringiz uchun. O'z branch'ingizni GitHub'ga yuborgandan keyin rebase qilish kerak bo'lsa, maxsus xavfsiz buyruq bor (git push --force-with-lease) — uni Ajralgan tarix darsida o'rganamiz.

7. Merge yoki rebase?

Ikkalasi ham bitta vazifani bajaradi — ikki chiziqdagi ishni birlashtiradi. Farqi tarixda:

Merge Rebase
Tarix shakli Haqiqiy: ayrilish va qo'shilish ko'rinadi Tekis chiziq, "go'yo ketma-ket"
Yangi commitlar Bitta merge commit Hamma commitlar qayta yaratiladi
Mavjud SHA'lar O'zgarmaydi O'zgaradi
Conflict Bir marta, hammasi birga Har commit uchun alohida
Vaziyat Tavsiya
O'z branch'ingizni main dagi yangiliklar bilan yangilash Rebase
Tayyor ishni main ga qo'shish Merge (yoki rebase + fast-forward)
Umumiy branch (main, boshqalar olgan branch) Faqat merge
Nima qilishni bilmasangiz Merge — u hech narsani qayta yozmaydi

Jamoalar o'z qoidasini tanlaydi. Ba'zilari tarix "haqiqiy" bo'lishini afzal ko'radi va faqat merge qiladi. Boshqalari tekis tarixni yaxshi ko'radi va har PR'dan oldin rebase talab qiladi. PR (pull request) — GitHub'da "branch'imni main ga qo'shing" degan so'rov; uni Pull Request darsida o'rganamiz. Ikkala yo'l ham to'g'ri — muhimi, oltin qoida buzilmasin.

8. git pull --rebase — kelajakka qisqa ko'prik

GitHub bilan ishlashni boshlaganingizda, git pull buyrug'i serverdagi yangiliklarni olib, sizning lokal ishingiz bilan birlashtiradi (Remote darsida). Standart holatda u merge qiladi va har safar "Merge branch 'main' of github.com/..." degan keraksiz commit yaratishi mumkin.

git pull --rebase esa birlashtirishni rebase bilan qiladi: sizning hali yuborilmagan commitlaringiz serverdagi yangiliklar ustiga qayta teriladi. Bu oltin qoidaga zid emas — qayta yoziladigan commitlar faqat sizda, hali hech kimga berilmagan. Ko'p dasturchilar buni doimiy qilib qo'yadi: git config --global pull.rebase true. Hozir sozlamang — bu mavzuni Ajralgan tarix darsida to'liq ko'ramiz.

9. Ko'p uchraydigan xatolar

9.1 Iflos ishchi papka

Commit qilinmagan o'zgarish bor paytda rebase boshlab bo'lmaydi:

bash
git rebase main
git status -s
text
error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.
 M b.txt

Tarjimasi: "rebase qilib bo'lmaydi: sizda staging'ga qo'shilmagan o'zgarishlar bor. Ularni commit yoki stash qiling".

Git ishingizni himoya qildi. Tuzatish: commit qiling yoki git restore bilan qaytaring (Stash darsida uchinchi yo'lni ko'rasiz).

9.2 add qilmay --continue

Conflictli faylni tahrirlab, git add ni unutsangiz:

text
menyu/index.html: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add

"menyu/index.html: birlashtirish kerak. Barcha merge ziddiyatlarini tahrirlab, keyin git add bilan hal qilingan deb belgilashingiz kerak". Fayl tahrirlangan bo'lsa ham, Git git add qilinmaguncha uni hal qilinmagan deb hisoblaydi. Tuzatish: git add <fayl>, keyin yana git rebase --continue.

9.3 Rebase yo'q paytda --continue

bash
git rebase --continue
text
fatal: no rebase in progress

"Hech qanday rebase ketmayapti" — rebase allaqachon tugagan yoki --abort qilingan. Hech narsa qilish shart emas: git status bilan holatni tekshiring.

9.4 Noto'g'ri yo'nalish

main da turib git rebase feature/x yozish — main ning commitlarini feature ustiga ko'chirish demak. Bu oltin qoidani buzadi. Qoida: rebase o'z branch'ingizda turib, main nomi bilan: git switch feature/x, keyin git rebase main. Yoki bitta buyruq bilan: git rebase main feature/x — Git avval feature/x ga o'tadi, keyin uni main ustiga ko'chiradi.

9.5 Rebase'dan keyin "commitlarim yo'qoldi"

Aslida yo'qolmagan — ular yangi SHA bilan yangi joyda. Tekshirish: git log --oneline --graph --all. Natija yoqmasa — darhol git reset --hard ORIG_HEAD.

10. Mashqlar

1-mashq (oson): Rostmi yoki yolg'on?

  1. git rebase main dan keyin branch'dagi commitlarning SHA'lari o'zgarmaydi.
  2. Rebase'dan keyin main ga merge odatda fast-forward bo'ladi.
  3. Rebase paytidagi conflict'da <<<<<<< HEAD ostida sizning commitingiz turadi.
  4. GitHub'ga yuborilgan, hamkasbingiz olgan branch'ni rebase qilish xavfsiz.
Yechim
  1. Yolg'on — rebase yangi commitlar yaratadi, ota commit o'zgargani uchun SHA ham o'zgaradi.
  2. Rost — branch main uchining to'g'ridan-to'g'ri davomi bo'lib qoladi.
  3. Yolg'on — HEAD rebase paytida yangi asos (main) tomoni; sizning commitingiz >>>>>>> yonida.
  4. Yolg'on — bu oltin qoidani buzadi: hamkasbingizda eski commitlar qoladi va tarix ikkiga bo'linadi.

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

Rebase paytida conflict chiqdi. Yechish ketma-ketligi:

bash
git rebase main
# CONFLICT (content): Merge conflict in menyu/index.html
git status
# VS Code'da markerlarni olib tashlaymiz
git  menyu/index.html
git rebase 

Rebase'dan butunlay voz kechish uchun: git rebase . Bitta conflictli commitni tashlab ketish uchun: git rebase .

Ishora: «Rebase paytida conflict» bo'limidagi hint: qatorlari to'rtala buyruqni ham aytadi.

Yechim
bash
git add menyu/index.html
git rebase --continue

Voz kechish — --abort (hammasi rebase'dan oldingi holatga qaytadi), tashlab ketish — --skip (faqat joriy commit tashlanadi, qolganlari davom etadi). git commit yozilmaydi — rebase commitni o'zi yaratadi.

3-mashq (qiyin): Ikki argumentli rebase

Mashq mashqlar reposida, 07/18-rebase/ papkasida bo'ladi. Har echo dan keyin git add . va git commit -m "07/18: <harf>" qiling:

bash
cd ~/kurs/mashqlar
mkdir -p 07/18-rebase
cd 07/18-rebase
echo A > a.txt       # commit "07/18: A"
git switch -c feature/harflar
echo B > b.txt       # commit "07/18: B"
echo C > c.txt       # commit "07/18: C"
git switch main
echo D > d.txt       # commit "07/18: D"
  1. git log --oneline --graph --all -4 ni chizing — qayerda ayrilish?
  2. main da turgan holda bitta buyruq bilan feature/harflar ni main ustiga ko'chiring.
  3. Buyruqdan keyin qaysi branch'dasiz? B va C ning SHA'lari o'zgardimi?
  4. main ga qaytib, branch'ni fast-forward bilan qo'shing va o'chiring.

Ishora: «Noto'g'ri yo'nalish» xatosidagi ikki argumentli shakl.

Yechim

Biz aynan shu buyruqlarni bajardik. Rebase'dan oldin:

text
* 968b904 (HEAD -> main) 07/18: D
| * e6317a2 (feature/harflar) 07/18: C
| * 09eae02 07/18: B
|/  
* 2eac35b 07/18: A

Buyruq va natija:

bash
git rebase main feature/harflar
git branch
git log --oneline --graph --all -4
text
Successfully rebased and updated refs/heads/feature/harflar.
* feature/harflar
  main
* 82057e4 (HEAD -> feature/harflar) 07/18: C
* c141db5 07/18: B
* 968b904 (main) 07/18: D
* 2eac35b 07/18: A

Siz endi feature/harflar dasiz — ikki argumentli rebase avval shu branch'ga o'tadi. B (09eae02 → c141db5) va C (e6317a2 → 82057e4) yangi SHA oldi, chunki ularning asosi A dan D ga ko'chdi. Sizda SHA'lar boshqacha bo'ladi, lekin o'zgarish fakti bir xil.

4-qadam:

bash
git switch main
git merge feature/harflar
git branch -d feature/harflar
text
Switched to branch 'main'
Updating 968b904..82057e4
Fast-forward
 07/18-rebase/b.txt | 1 +
 07/18-rebase/c.txt | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 07/18-rebase/b.txt
 create mode 100644 07/18-rebase/c.txt
Deleted branch feature/harflar (was 82057e4).

Fast-forward — rebase'dan keyin merge commit kerak bo'lmadi.

4-mashq: Portfolio qadami — branch'ni yangilab qo'shish

Portfolio'da "Loyihalar" sahifasiga landing'ingizga havola qo'shamiz. Shu orada main da boshqa kichik ish bajariladi — va branch'ni rebase bilan yangilaymiz.

  1. feature/landing-havola branch'ini oching. sayt/loyihalar/index.html ga landing havolasini qo'shing (masalan, <a href="/landing/">Landing: Bahor</a>). Commit: Loyihalar: landing havolasini qo'sh.
  2. main ga qayting va sayt/404.html ga tushuntiruvchi jumla qo'shing. Commit: 404: tushuntirish matnini qo'sh.
  3. feature/landing-havola ga o'tib, git rebase main.
  4. main ga qaytib, merge qiling — fast-forward bo'lishi kerak. Branch'ni o'chiring.
  5. git log --oneline -4 bilan tekshiring: merge commit yo'q, tarix tekis.
Yechim
bash
cd ~/kurs/portfolio
git switch -c feature/landing-havola
# loyihalar sahifasiga havola
git commit -am "Loyihalar: landing havolasini qo'sh"
git switch main
# 404 sahifasiga jumla
git commit -am "404: tushuntirish matnini qo'sh"
git switch feature/landing-havola
git rebase main
git switch main
git merge feature/landing-havola
git branch -d feature/landing-havola
git log --oneline -4

Qisqa sinov portfolio'sida rebase'dan oldin va keyin:

text
* cbc0687 (main) 404: tushuntirish matnini qo'sh
| * 01567ef (HEAD -> feature/landing-havola) Loyihalar: landing havolasini qo'sh
|/  
*   868a51c Merge branch 'feature/footer-ism'
...
* b61fb7a (HEAD -> feature/landing-havola) Loyihalar: landing havolasini qo'sh
* cbc0687 (main) 404: tushuntirish matnini qo'sh
*   868a51c Merge branch 'feature/footer-ism'
...

Merge va oxirgi tarix:

text
Updating cbc0687..b61fb7a
Fast-forward
 sayt/loyihalar/index.html | 1 +
 1 file changed, 1 insertion(+)
b61fb7a (HEAD -> main) Loyihalar: landing havolasini qo'sh
cbc0687 404: tushuntirish matnini qo'sh
868a51c Merge branch 'feature/footer-ism'
dfcc3ec Footer: shaharni qo'sh

Havola commiti SHA'sini o'zgartirdi (01567ef → b61fb7a) — bu normal, branch hali hech kimga berilmagan edi. Portfolio hali GitHub'ga ulanmagan, shuning uchun oltin qoida bu yerda buzilmaydi.

11. Real ishda

  • "Rebase qilib yuboring". PR'ingiz eskirib qolsa, reviewer ko'pincha shunday so'raydi: branch'ingizni yangi main ustiga olib keling. Bu aynan git rebase main (keyin xavfsiz push — Ajralgan tarix).
  • GitHub'dagi "Rebase and merge" tugmasi PR commitlarini main ustiga rebase qilib qo'shadi (Pull Request).
  • Tekis tarix git log, blame va xatoni topishni osonlashtiradi — shuning uchun ko'p jamoalar rebase'ni afzal ko'radi.
  • Intervyuda klassik savol: "Merge va rebase farqi nima? Qachon rebase qilmaysiz?" Kuchli javob — SHA qayta yozilishi va oltin qoida.

Xulosa

  • git rebase main joriy branch commitlarini main uchiga qayta qo'yadi — tarix tekis, keyingi merge fast-forward.
  • Rebase yangi commitlar yaratadi: ota o'zgargani uchun SHA'lar o'zgaradi; eski uch ORIG_HEAD da.
  • Conflict'da: yechish → git add → git rebase --continue; qochish — --abort; commitni tashlash — --skip.
  • Rebase paytida HEAD — main tomoni, sizning commitingiz >>>>>>> yonida.
  • Oltin qoida: umumiy, boshqalar olgan branch'ni rebase qilmang; bilmasangiz — merge.

Keyingi dars: Interaktiv rebase: PR'dan oldin tarixni tozalash — rebase'ning pick ro'yxatini o'zingiz tahrirlab, chalkash commitlarni birlashtirish, qayta nomlash va o'chirishni o'rganamiz.

Manbalar

  • Pro Git kitobi: "Git Branching — Rebasing" (ayniqsa "The Perils of Rebasing") — git-scm.com/book
  • Git hujjati: "git-rebase", "git-pull" (--rebase) — git-scm.com/docs
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Git rebase: tarixni chiziqlash va oltin qoida — IlmHamroh