IlmHamroh
JavaScript Full-stack/7-qism. Git va GitHub asoslari16/36-dars19 daqiqa
Mundarija (31)

Git merge: fast-forward va uch tomonlama birlashtirish

Qisqacha: git merge <branch> boshqa branch'dagi ishni joriy branch'ga qo'shadi. Agar joriy branch o'sha vaqtda oldinga ketmagan bo'lsa, Git shunchaki ko'rsatkichni suradi — bu fast-forward. Ikkala tomonda ham yangi commit bo'lsa, Git umumiy ajdod (merge base) va ikki uchni solishtirib, ikki otali merge commit yaratadi. --no-ff har doim merge commit qiladi, --ff-only esa faqat fast-forward'ga ruxsat beradi.

Bu darsda

  • git merge bilan branch'dagi ishni main ga qo'shasiz.
  • Fast-forward va uch tomonlama birlashtirishni natijasidan ajrata olasiz.
  • Merge base nima ekanini va Git uni nega qidirishini tushuntirasiz.
  • Merge commitning ikki otasini git cat-file bilan o'z ko'zingiz bilan ko'rasiz.
  • --no-ff va --ff-only ni qachon ishlatishni bilasiz.

Oldin bilishingiz kerak: Branch nima: arzon ko'rsatkich, Git ichkaridan: obyektlar, SHA va snapshot, Tarixni o'qish: git log.

1. Nega bu kerak?

Oldingi darsda «Bahor» tarixi ikkiga bo'lindi. main da shashlik narxi bor, feature/bron-forma da esa forma. Forma tayyor. Endi u saytga — ya'ni main ga — chiqishi kerak.

Branch'ning butun ma'nosi shu: alohida ishlash, keyin birlashtirish. Birlashtira olmasak, branch yarim ish bo'lib qoladi. Git'da bu ishni git merge qiladi.

Ikki ariqni tasavvur qiling. Bir ariq ikkinchisidan ajralib, bir oz yurib, yana qo'shiladi. Qo'shilish joyida ikkala ariqning suvi birga oqadi. Merge ham shunday: ikki chiziqdagi o'zgarishlar bitta chiziqqa tushadi.

Git buni ikki xil yo'l bilan qiladi. Qaysi yo'lni tanlashini o'zi hal qiladi — tarixning shakliga qarab. Ikkalasini ham ko'rib chiqamiz.

2. Fast-forward: ko'rsatkichni surish

2.1 Vaziyat

Oldingi darsning mashqida aloqa sahifasiga manzil yozish uchun fix/aloqa-manzil branch'ini ochgan edik. Buni «Bahor»da qilmagan bo'lsangiz, hozir qiling:

bash
cd ~/kurs/bahor
git switch -c fix/aloqa-manzil
echo "<p>Manzil: Toshkent, Bahor ko'chasi 7</p>" >> aloqa/index.html
git add aloqa/index.html
git commit -m "Aloqa: manzilni qo'sh"
git switch main
text
Switched to a new branch 'fix/aloqa-manzil'
[fix/aloqa-manzil bba9aee] Aloqa: manzilni qo'sh
 1 file changed, 1 insertion(+)
Switched to branch 'main'

Tarixga qaraymiz:

bash
git log --oneline --graph --all
text
* bba9aee (fix/aloqa-manzil) Aloqa: manzilni qo'sh
* 297cd7e (HEAD -> main) Menyu: shashlik narxini qo'sh
| * d6772a4 (feature/bron-forma) Bron: telefon maydonini qo'sh
| * 108e327 Bron: formani qo'sh
|/  
* 1db8b60 Rasm: choy suratini qo'sh
* 56b3259 Menyu: somsa narxini qo'sh
...

(Pastki qatorlar o'zgarmagani uchun ... bilan qisqartirdik.) Diqqat qiling: fix/aloqa-manzil main bilan bitta chiziqda, undan bir qadam oldinda. main o'sha branch ochilgandan beri joyidan qo'zg'almagan.

2.2 Merge

Qoida: siz qaysi branch'da tursangiz, ish o'sha branch'ga qo'shiladi. Biz main damiz va fix/aloqa-manzil ni unga olib kelamiz:

bash
git merge fix/aloqa-manzil
text
Updating 297cd7e..bba9aee
Fast-forward
 aloqa/index.html | 1 +
 1 file changed, 1 insertion(+)

Qatorma-qator:

  • Updating 297cd7e..bba9aee — "main 297cd7e dan bba9aee ga yangilanmoqda".
  • Fast-forward — "oldinga o'tkazish". Yangi commit yaratilmadi.
  • Qolgani — qaysi fayllar o'zgargani, xuddi commit natijasidagidek.

2.3 Aslida nima bo'ldi?

bash
git log --oneline --graph --all
text
* bba9aee (HEAD -> main, fix/aloqa-manzil) Aloqa: manzilni qo'sh
* 297cd7e Menyu: shashlik narxini qo'sh
| * d6772a4 (feature/bron-forma) Bron: telefon maydonini qo'sh
| * 108e327 Bron: formani qo'sh
|/  
* 1db8b60 Rasm: choy suratini qo'sh
* 56b3259 Menyu: somsa narxini qo'sh
...

main endi bba9aee da — fix/aloqa-manzil bilan yonma-yon. Git hech narsani "birlashtirmadi". U shunchaki main ko'rsatkichini chiziq bo'ylab oldinga surdi. Oldingi darsda ko'rganimizdek, branch — 41 baytlik fayl. Fast-forward shu faylga yangi SHA yozishdan iborat.

gitGraph
  commit id: "1db8b60"
  commit id: "297cd7e shashlik"
  branch fix/aloqa-manzil
  commit id: "bba9aee manzil"
  checkout main
  merge fix/aloqa-manzil

Nimaga qarang: diagramma chizish qoidasi tufayli oxirida birlashish nuqtasi ko'rinadi. Haqiqiy tarixda esa yangi commit yo'q — git log --graph natijasidagi to'g'ri chiziq aynan shuni aytadi. main bba9aee ga yetib keldi, xolos.

Fast-forward faqat bitta holatda mumkin: joriy branch'ning oxirgi commiti qo'shilayotgan branch tarixida bor bo'lsa. Ya'ni joriy branch "orqada qolgan", lekin yo'ldan chiqmagan. Xuddi mashina bitta yo'lda old tomondagisiga yetib olgandek.

2.4 Ikkinchi marta merge

Xuddi shu buyruqni yana bir marta yozamiz:

bash
git merge fix/aloqa-manzil
text
Already up to date.

"Allaqachon yangilangan" — qo'shadigan hech narsa yo'q. Xato emas.

Branch'ning ishi main da. Endi uni o'chirish xavfsiz — -d rad etmaydi:

bash
git branch -d fix/aloqa-manzil
text
Deleted branch fix/aloqa-manzil (was bba9aee).

Tekshirib ko'ring: Fast-forward'dan keyin git log da yangi commit paydo bo'ladimi?

Javob

Yo'q. Fast-forward hech qanday commit yaratmaydi — faqat main ko'rsatkichini mavjud commitga ko'chiradi. Tarixda o'sha-o'sha commitlar, faqat main yorlig'i boshqa joyda.

3. Uch tomonlama merge

3.1 Tarix ayrilgan bo'lsa

Endi forma. feature/bron-forma 1db8b60 dan ajralgan, main esa o'shandan beri ikki qadam yurdi: shashlik va manzil. Bu safar fast-forward mumkin emas. Buni --ff-only bayrog'i bilan tekshirib ko'ramiz — u "faqat fast-forward bo'lsa birlashtir, aks holda hech narsa qilma" degani:

bash
git merge --ff-only feature/bron-forma
text
hint: Diverging branches can't be fast-forwarded, you need to either:
hint:
hint: 	git merge --no-ff
hint:
hint: or:
hint:
hint: 	git rebase
hint:
hint: Disable this message with "git config set advice.diverging false"
fatal: Not possible to fast-forward, aborting.

Tarjimasi: "Ayrilgan branch'larni fast-forward qilib bo'lmaydi, sizga yo git merge --no-ff, yo git rebase kerak. Fast-forward mumkin emas, to'xtatildi". Hech narsa o'zgarmadi. Git maslahat berayotgan ikkinchi yo'l — rebase — Rebase darsida. Hozir birinchi yo'l: haqiqiy birlashtirish.

3.2 Merge base — umumiy ajdod

Ikki chiziqni birlashtirish uchun Git avval ular qayerda ajralganini topadi. Bu nuqta merge base (umumiy ajdod) deyiladi. Uni so'rash mumkin:

bash
git merge-base main feature/bron-forma
text
1db8b6069b0c968277284b43cdf79a6d629a5515

Bu — 1db8b60, choy surati commiti: oldingi darsning diagrammasidagi ayrilish nuqtasi. Git nega uni qidiradi? Chunki faqat ikki uchni solishtirish yetmaydi.

Misol. bron/index.html fayli main da bitta qatorli, feature/bron-forma da esa olti qatorli. Faqat shu ikkitasiga qarab, Git bilolmaydi: forma bir tomonda qo'shildimi yoki ikkinchi tomonda o'chirildimi? Umumiy ajdodga qaraydi: u yerda fayl bitta qatorli edi. Demak main faylga tegmagan, feature/bron-forma esa formani qo'shgan. Natijaga forma kiradi.

Shuning uchun nomi — uch tomonlama merge (three-way merge). Git uchta versiyani solishtiradi:

Versiya «Bahor»da Nima beradi
Merge base 1db8b60 Ajralishdan oldingi holat
Joriy branch uchi main — bba9aee Bir tomonda nima o'zgargan
Qo'shilayotgan branch uchi feature/bron-forma — d6772a4 Ikkinchi tomonda nima o'zgargan

Har bir fayl bo'lagi uchun Git so'raydi: "kim o'zgartirdi?" Faqat bir tomon o'zgartirgan bo'lsa — o'sha o'zgarish olinadi. Hech kim tegmagan bo'lsa — o'z holicha qoladi. Ikkala tomon bir joyni turlicha o'zgartirgan bo'lsa — Git o'zi hal qilmaydi. Bu conflict (konflikt) — Git qarorni sizga qoldiradi. Uni keyingi darsda yechamiz.

3.3 Merge commit xabari

bash
git merge feature/bron-forma

Bu safar Git sizdan xabar so'raydi: VS Code'da MERGE_MSG nomli tab ochiladi. Ichida tayyor xabar va izohlar bor. Biz uni muharrir o'rniga ekranga chiqarib ko'rdik:

text
Merge branch 'feature/bron-forma'
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

Tarjimasi (izohlar): "Bu merge nega kerakligini tushuntiruvchi xabar kiriting. # bilan boshlangan qatorlar hisobga olinmaydi, bo'sh xabar commitni bekor qiladi". Birinchi qator — Git tayyorlagan xabar: Merge branch 'feature/bron-forma'. Odatda uni o'zgartirmay, tabni yopish kifoya. Muharrir ochilmasin desangiz — git merge --no-edit feature/bron-forma.

Tab yopilgach:

text
Merge made by the 'ort' strategy.
 bron/index.html | 5 +++++
 1 file changed, 5 insertions(+)

"Merge 'ort' strategiyasi bilan qilindi". ort — Git 2.34 dan beri standart birlashtirish algoritmining nomi. Uni tanlash yoki sozlash hech qachon kerak bo'lmaydi.

3.4 Natija — ikki otali commit

bash
git log --oneline --graph --all
text
*   fd7b1ae (HEAD -> main) Merge branch 'feature/bron-forma'
|\  
| * d6772a4 (feature/bron-forma) Bron: telefon maydonini qo'sh
| * 108e327 Bron: formani qo'sh
* | bba9aee Aloqa: manzilni qo'sh
* | 297cd7e Menyu: shashlik narxini qo'sh
|/  
* 1db8b60 Rasm: choy suratini qo'sh
* 56b3259 Menyu: somsa narxini qo'sh
...

Yuqorida yangi commit — fd7b1ae. Undan ikki chiziq pastga tushadi (|\): biri main ning oldingi uchiga, biri forma branch'iga. Pastda esa |/ — ikki chiziq ajralgan joy.

gitGraph
  commit id: "1db8b60"
  branch feature/bron-forma
  commit id: "108e327 forma"
  commit id: "d6772a4 telefon"
  checkout main
  commit id: "297cd7e shashlik"
  commit id: "bba9aee manzil"
  merge feature/bron-forma id: "fd7b1ae merge"

Nimaga qarang: merge commit ikkala chiziqning uchidan o'q oladi. Shuning uchun uning ikki otasi bor. Oddiy commitda ota bitta.

Buni isbotlaymiz. Git ichkaridan darsidagi git cat-file -p commit obyektini ochib ko'rsatadi:

bash
git cat-file -p HEAD
text
tree 684db739e34f20839714c277b913dfbf8076e23c
parent bba9aee76021f03a510ed1a7a9c7080be9ed8315
parent d6772a4be7fbfc3abe118e9899f6dac0c8d1ed11
author Aziz Karimov <aziz@example.com> 1791952200 +0500
committer Aziz Karimov <aziz@example.com> 1791952200 +0500

Merge branch 'feature/bron-forma'

Ikkita parent qatori! Birinchisi — merge paytida siz turgan branch (main) uchi. Ikkinchisi — qo'shilgan branch uchi. Tarixni o'qish darsidagi HEAD^ yozuvi aslida HEAD^1 — birinchi ota. Ikkinchisiga HEAD^2 bilan murojaat qilinadi:

bash
git log --oneline -1 HEAD^1
git log --oneline -1 HEAD^2
text
bba9aee Aloqa: manzilni qo'sh
d6772a4 (feature/bron-forma) Bron: telefon maydonini qo'sh

3.5 Faqat asosiy chiziq: --first-parent

Merge commitli tarixda ba'zan faqat main ning o'z qadamlari kerak bo'ladi. --first-parent har merge commitda faqat birinchi otaga yuradi:

bash
git log --oneline --first-parent
text
fd7b1ae (HEAD -> main) Merge branch 'feature/bron-forma'
bba9aee Aloqa: manzilni qo'sh
297cd7e Menyu: shashlik narxini qo'sh
1db8b60 Rasm: choy suratini qo'sh
...

Forma ichidagi ikki commit ko'rinmaydi — ular bitta "Merge branch" qatoriga yig'ilgan. Katta loyihalarda main tarixini shu tarzda o'qish qulay: har qator — bitta tugallangan ish.

Branch endi --merged ro'yxatida — uni o'chirsak bo'ladi:

bash
git branch --merged
git branch -d feature/bron-forma
text
  feature/bron-forma
* main
Deleted branch feature/bron-forma (was d6772a4).

Branch o'chdi, lekin uning ikki commiti tarixda qoladi — merge commitning ikkinchi otasi orqali. Branch nomi faqat ish davomida kerak edi.

Tekshirib ko'ring: Merge commitda nega aynan ikkita parent bor? Birinchi va ikkinchi ota o'rnini nima belgilaydi?

Javob

Merge commit ikki tarixni birlashtiradi, shuning uchun ikkalasining uchiga bog'lanadi. Birinchi ota — merge paytida siz turgan branch uchi (bizda main). Ikkinchi ota — git merge ga nomi berilgan branch uchi. Agar feature/bron-forma da turib git merge main qilganimizda, tartib teskari bo'lardi.

4. --no-ff: har doim merge commit

4.1 Muammo

Fast-forward tarixni toza saqlaydi, lekin bitta narsani yo'qotadi. Aloqa sahifasiga yo'l ko'rsatkich qo'shish uchun ikki commitli branch ochamiz:

bash
git switch -c feature/aloqa-xarita
echo '<h2>Bizni qanday topasiz</h2>' >> aloqa/index.html
git add aloqa/index.html
git commit -m "Aloqa: yo'l ko'rsatkich sarlavhasini qo'sh"
echo '<p>Metro: Bodomzor bekatidan 5 daqiqa</p>' >> aloqa/index.html
git add aloqa/index.html
git commit -m "Aloqa: metro bekatini qo'sh"
git switch main
text
Switched to a new branch 'feature/aloqa-xarita'
[feature/aloqa-xarita 2c5510a] Aloqa: yo'l ko'rsatkich sarlavhasini qo'sh
 1 file changed, 1 insertion(+)
[feature/aloqa-xarita 8da0793] Aloqa: metro bekatini qo'sh
 1 file changed, 1 insertion(+)
Switched to branch 'main'

main bu orada yurmadi, shuning uchun oddiy git merge fast-forward qiladi. Natijada ikki commit main chizig'iga tekis tushadi. Bir oydan keyin tarixga qarasangiz, "bu ikki commit bitta ishning qismlari edi" degan ma'lumot qolmaydi.

4.2 Yechim

--no-ff (no fast-forward) Git'ga aytadi: "fast-forward mumkin bo'lsa ham, merge commit yarat":

bash
git merge --no-ff feature/aloqa-xarita
git log --oneline --graph -9
text
Merge made by the 'ort' strategy.
 aloqa/index.html | 2 ++
 1 file changed, 2 insertions(+)
*   c3673b8 (HEAD -> main) Merge branch 'feature/aloqa-xarita'
|\  
| * 8da0793 (feature/aloqa-xarita) Aloqa: metro bekatini qo'sh
| * 2c5510a Aloqa: yo'l ko'rsatkich sarlavhasini qo'sh
|/  
*   fd7b1ae Merge branch 'feature/bron-forma'
|\  
| * d6772a4 Bron: telefon maydonini qo'sh
| * 108e327 Bron: formani qo'sh
* | bba9aee Aloqa: manzilni qo'sh
* | 297cd7e Menyu: shashlik narxini qo'sh
|/  
* 1db8b60 Rasm: choy suratini qo'sh

(Bu yerda ham VS Code'da xabar tabi ochiladi — yopamiz.) Endi tarixda "cho'ntak" bor: ikki commit bitta merge ostida guruhlangan. Bu cho'ntakning pastki uchi to'g'ridan-to'g'ri oldingi merge'ga tutashadi — main o'rtada yurmagani shundan ko'rinadi.

gitGraph
  commit id: "fd7b1ae merge"
  branch feature/aloqa-xarita
  commit id: "2c5510a sarlavha"
  commit id: "8da0793 metro"
  checkout main
  merge feature/aloqa-xarita id: "c3673b8 merge"

Nimaga qarang: main chizig'ida yangi commit yo'q edi, lekin merge commit baribir yaratildi. Endi git log --first-parent da bu ish bitta qator bo'lib ko'rinadi.

bash
git branch -d feature/aloqa-xarita

4.3 Qaysi biri yaxshi?

Usul Tarix Qachon
Fast-forward To'g'ri chiziq, merge commit yo'q Bitta kichik commit, shaxsiy loyiha
--no-ff Har ish — alohida cho'ntak Bir necha commitli ish, jamoa loyihasi
--ff-only Faqat to'g'ri chiziq, bo'lmasa to'xtaydi "Tasodifan merge commit qilib qo'ymay" degan ehtiyot

Yagona to'g'ri javob yo'q — jamoalar o'zi kelishadi. GitHub'dagi Pull Request tugmasi standart holatda --no-ff kabi ishlaydi: har PR — bitta merge commit. Buni Pull Request darsida ko'rasiz. --ff-only esa Ajralgan tarix darsida git pull bilan birga yana uchraydi.

Tekshirib ko'ring: main oldinga ketmagan paytda git merge --no-ff feature/x va git merge feature/x natijasida main dagi fayllar farq qiladimi?

Javob

Yo'q, fayllar bir xil. Ikkala holatda ham main feature/x dagi barcha o'zgarishlarni oladi. Farq faqat tarix shaklida: --no-ff qo'shimcha merge commit yaratadi va ish alohida cho'ntakda ko'rinadi.

5. Ko'p uchraydigan xatolar

5.1 Noto'g'ri yo'nalish

Eng ko'p xato — merge'ni teskari branch'da qilish. Aziz forma branch'ida turib git merge main yozdi va "nega main da forma yo'q?" deb hayron. Qoida: siz turgan branch o'zgaradi, nomi yozilgan branch — yo'q. main ga olib kelish uchun avval git switch main, keyin git merge feature/.... Merge'dan oldin git branch --show-current yoki promptdagi nomga qarang.

5.2 Branch nomida xato

bash
git merge feature/menyu
text
merge: feature/menyu - not something we can merge

Tarjimasi: "feature/menyu — birlashtirsa bo'ladigan narsa emas". Bunday branch yo'q. Git "branch topilmadi" demaydi, chunki git merge ga commit SHA'si yoki tag ham berish mumkin — u shunchaki bu nomni hech narsaga bog'lay olmadi. Tuzatish: git branch bilan to'g'ri nomni tekshiring, Tab bilan to'ldiring.

5.3 Saqlanmagan o'zgarish

Rustam fix/aloqa-tel branch'ida aloqa sahifasiga telefon raqamini yozdi. Siz esa main da o'sha faylni o'zgartirib, commit qilmay turibsiz:

bash
git status -s
git merge fix/aloqa-tel
text
 M aloqa/index.html
Updating c3673b8..076bc39
error: Your local changes to the following files would be overwritten by merge:
	aloqa/index.html
Please commit your changes or stash them before you merge.
Aborting

Tarjimasi: "Quyidagi fayllardagi mahalliy o'zgarishlaringiz merge tufayli ustidan yozilib ketadi. Merge'dan oldin commit qiling yoki stash qiling. To'xtatildi". Branch nima darsidagi git switch xatosining egizagi. Git sizning saqlanmagan ishingizni himoya qildi — hech narsa o'zgarmadi.

Tuzatish: ishingizni commit qiling yoki kerak bo'lmasa git restore bilan qaytaring, keyin merge'ni takrorlang:

bash
git restore aloqa/index.html
git merge fix/aloqa-tel
text
Updating c3673b8..076bc39
Fast-forward
 aloqa/index.html | 1 +
 1 file changed, 1 insertion(+)

Maslahat: Merge'dan oldingi odat — git status. "working tree clean" bo'lmasa, merge qilmang.

5.4 Merge commit xabarini bo'sh qoldirish

VS Code'da MERGE_MSG tabidagi Merge branch ... qatorini ham o'chirib yopsangiz, Git merge commitni yaratmaydi:

text
error: Empty commit message.
Not committing merge; use 'git commit' to complete the merge.

Tarjimasi: "xato: commit xabari bo'sh. Merge commit qilinmadi; merge'ni yakunlash uchun git commit ishlating". Lekin merge jarayoni to'xtab qolgan holatda turadi: git status "All conflicts fixed but you are still merging" deydi. Tuzatish: git commit yozing — muharrir yana ochiladi, bu safar xabarni qoldiring.

5.5 "Merge — branch'ni o'chiradi"

Yo'q. git merge qo'shilgan branch'ga tegmaydi — u joyida qoladi. O'chirish alohida qadam: git branch -d. Ko'p boshlovchilarda o'nlab eski branch to'planib qoladi. Odat: merge'dan keyin darhol -d.

6. Mashqlar

1-mashq (oson): Fast-forward yoki merge commit?

Har holatda git switch main va git merge feature/x dan keyin nima bo'ladi — fast-forward yoki merge commit?

  1. feature/x main dan ochilgan, unda 3 ta commit. main da shu orada hech narsa bo'lmagan.
  2. feature/x da 1 ta commit. Shu orada main ga boshqa branch qo'shilgan.
  3. 1-holat, lekin buyruq git merge --no-ff feature/x.
  4. 2-holat, lekin buyruq git merge --ff-only feature/x.
Yechim
  1. Fast-forward — main o'z joyida turibdi, feature/x undan oldinda.
  2. Merge commit — ikkala tomonda yangi commit bor, tarix ayrilgan.
  3. Merge commit — --no-ff fast-forward'ni taqiqlaydi.
  4. Hech narsa bo'lmaydi: fatal: Not possible to fast-forward, aborting. Tarix ayrilgan, --ff-only esa faqat fast-forward'ga ruxsat beradi.

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

Bosh sahifaga Telegram kanal havolasi qo'shamiz. «Bahor» tarixini buzmaslik uchun mashqni sinov-git dagi yangi kichik repoda qiling. Ish tarixda alohida cho'ntak bo'lib qolsin:

bash
cd ~/kurs/sinov-git
git init telegram
cd telegram
echo '<h1>Bahor</h1>' > index.html
git add index.html
git commit -m "Bosh sahifa: sahifa yarat"
git switch -c feature/telegram
echo '<a href="https://t.me/sizning_kanal">Telegram</a>' >> index.html
git add index.html
git commit -m "Bosh sahifa: Telegram havolasini qo'sh"
git switch 
git merge  feature/telegram
git branch  feature/telegram

Ishora: merge siz turgan branch'ga qo'shiladi; cho'ntak — «--no-ff: har doim merge commit» bo'limi; o'chirish — Branch nima.

Yechim
bash
git switch main
git merge --no-ff feature/telegram
git branch -d feature/telegram
git log --oneline --graph -4

git merge --no-ff VS Code'da xabar tabini ochadi — yopasiz. -d xatosiz o'chiradi, chunki branch'ning ishi endi main da. Oxirgi buyruq natijasi:

text
*   ec78e0c (HEAD -> main) Merge branch 'feature/telegram'
|\  
| * 5114f19 Bosh sahifa: Telegram havolasini qo'sh
|/  
* c8cc6d1 Bosh sahifa: sahifa yarat

main shu orada yurmagan bo'lsa ham, merge commit bor — --no-ff shuni ta'minladi.

3-mashq (qiyin): Otalarni toping

Tashlab yuboriladigan repoda shunday tarix yarating (har echo dan keyin git add . va git commit -m "<harf>"):

bash
cd ~/kurs/sinov-git
git init mashq16
cd mashq16
echo A > a.txt       # commit "A"
git switch -c x
echo B > b.txt       # commit "B"
git switch main
echo C > c.txt       # commit "C"
git merge x
  1. Oxirgi buyruq fast-forward qiladimi yoki merge commit?
  2. Merge commitning birinchi va ikkinchi otasi qaysi commitlar?
  3. git merge-base main x merge'dan oldin nima qaytargan bo'lardi?

Ishora: tarix ayrilganmi — «Uch tomonlama merge» bo'limi; otalar tartibi — HEAD^1 va HEAD^2.

Yechim

Biz aynan shu buyruqlarni bajardik. Merge natijasi va tarix:

text
Merge made by the 'ort' strategy.
 b.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 b.txt
*   c23b13f (HEAD -> main) Merge branch 'x'
|\  
| * 5471ce1 (x) B
* | 14e4c61 C
|/  
* 33d8df9 A
  1. Merge commit: main da C, x da B — tarix ayrilgan.
  2. Birinchi ota — C (main uchi, siz turgan branch), ikkinchi ota — B (x uchi). Tekshirish: git log --oneline -1 HEAD^2.
  3. A commitining SHA'si — ikkala chiziq shu yerdan ajralgan.

create mode 100644 b.txt — yangi fayl main ga merge orqali keldi. SHA'lar sizda boshqacha bo'ladi.

4-mashq: Portfolio qadami — birinchi merge

Oldingi darsda portfolio'da feature/git-konikma branch'ini ochgan edingiz. Endi uni main ga qo'shamiz. Keyin yana bitta kichik ishni --no-ff bilan qilamiz.

  1. ~/kurs/portfolio da git log --oneline --graph --all bilan holatni ko'ring.
  2. main ga o'tib, feature/git-konikma ni birlashtiring. Fast-forward bo'ldimi?
  3. Branch'ni -d bilan o'chiring.
  4. feature/aloqa-telegram branch'ini oching. Aloqa sahifasiga Telegram havolasi qo'shing: <a href="https://t.me/sizning_kanal">Telegram</a> (sizning_kanal o'rniga o'zingiznikini yozing). Commit: Aloqa: Telegram havolasini qo'sh.
  5. main ga --no-ff bilan qo'shing va branch'ni o'chiring.
  6. git log --oneline --graph --all bilan natijani ko'ring.

mashqlar repo: shu darsning 1–3-mashq javoblarini mashqlar/07/16-merge/javoblar.md ga yozing va commit qiling: 07/16: merge mashqlari javoblarini qo'sh.

Yechim
bash
cd ~/kurs/portfolio
git log --oneline --graph --all
git switch main
git merge feature/git-konikma
git branch -d feature/git-konikma
git switch -c feature/aloqa-telegram
# VS Code'da sayt/aloqa/index.html ga havola qo'shing
git add sayt/aloqa/index.html
git commit -m "Aloqa: Telegram havolasini qo'sh"
git switch main
git merge --no-ff feature/aloqa-telegram
git branch -d feature/aloqa-telegram
git log --oneline --graph --all

Qisqa sinov portfolio'sidagi birinchi merge va oxirgi tarix:

text
Updating 086fe19..fc1e527
Fast-forward
 sayt/haqimda/index.html | 1 +
 1 file changed, 1 insertion(+)
*   ba79bb9 (HEAD -> main) Merge branch 'feature/aloqa-telegram'
|\  
| * af6f3e0 Aloqa: Telegram havolasini qo'sh
|/  
* fc1e527 Haqimda: Git ko'nikmasini qo'sh
* 086fe19 Git: qator oxirlarini .gitattributes bilan tartibla
* 63190c1 Portfolio: 06-qism oxiridagi holat

Birinchi merge — fast-forward: main shu orada yurmagan edi. Ikkinchisi — --no-ff tufayli cho'ntak. Sizda tarix uzunroq va SHA'lar boshqacha. Sayt hali GitHub'da yangilanmaydi — repo bog'lanmagan (Remote darsida bog'laymiz).

7. Real ishda

  • Pull Request = merge. GitHub'dagi "Merge pull request" tugmasi aynan shu darsdagi ishni serverda bajaradi. U yerda uch usul bor: merge commit, squash va rebase. Ularni Pull Request darsida solishtiramiz.
  • Kim merge qiladi? Jamoada main ga odatda o'zingiz emas, tekshiruvdan keyin tizim qo'shadi. Lekin lokal merge baribir har kuni kerak: main dagi yangiliklarni o'z branch'ingizga olish uchun.
  • --first-parent bilan hisobot. "Bu hafta nima chiqdi?" degan savolga git log --first-parent javob beradi — har qator bitta PR.
  • Intervyuda so'raladi: "Fast-forward va merge commit farqi?", "Merge commitning nechta otasi bor?" Bu darsdan keyin ikkalasiga ham misol bilan javob bera olasiz.

Xulosa

  • git merge <branch> shu branch'ning ishini siz turgan branch'ga qo'shadi.
  • Fast-forward — joriy branch orqada qolgan bo'lsa, ko'rsatkich shunchaki suriladi; yangi commit yo'q.
  • Tarix ayrilgan bo'lsa — uch tomonlama merge: merge base va ikki uch solishtirilib, ikki otali merge commit yaratiladi.
  • HEAD^1 — birinchi ota (siz turgan branch), HEAD^2 — qo'shilgan branch; --first-parent faqat asosiy chiziqni ko'rsatadi.
  • --no-ff har doim merge commit qiladi, --ff-only faqat fast-forward'ga ruxsat beradi.
  • Merge'dan oldin — git status toza bo'lsin, keyin — git branch -d.

Keyingi dars: Conflictlarni yechish amaliyoti — ikki kishi bitta qatorni turlicha o'zgartirsa, Git nima deydi va buni qanday xotirjam hal qilish kerak.

Manbalar

  • Pro Git kitobi: "Basic Branching and Merging" — git-scm.com/book
  • Git hujjati: "git-merge", "git-merge-base" — git-scm.com/docs
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Git merge: fast-forward va uch tomonlama birlashtirish — IlmHamroh