git merge — Fast-forward va 3-way merge, farqlari
Muammodan boshlaylik
feature/savat branch ida savat funksiyasi tayyor: 5 ta commit, testlar o'tadi. Endi u main ga qo'shilishi kerak — foydalanuvchilar uni ko'rishi uchun.
Lekin siz ishlayotgan paytda hamkasbingiz ham main ga 3 ta commit qo'shdi. Endi ikki tarix ajralgan. Ularni qanday birlashtirish kerak — hech narsani yo'qotmasdan?
Bu — merge (birlashtirish).
Asosiy qoida: qayerga qo'shilsa — o'sha yerda turing
git switch main # 1. QABUL qiluvchi branch ga o'tish
git merge feature/savat # 2. Qaysi branch ni qo'shish
git merge X — "X ni joriy branch ga qo'sh". Ko'p yangi boshlovchilar teskarisini qiladi — feature da turib git merge main — bu main ni feature ga qo'shadi (bu ham ba'zan kerak, lekin boshqa maqsadda).
1. Fast-forward — "oldinga surish"
Eng oddiy holat: siz feature/savat da ishlayotganingizda, main da hech narsa o'zgarmagan.
Oldin:
main
↓
●────●────●────●
\
●────●────●
↑
feature/savat
main ning barcha commitlari feature/savat da allaqachon bor. Birlashtirish uchun yangi narsa yaratish shart emas — main ko'rsatkichini shunchaki oldinga surish yetarli:
git switch main
git merge feature/savat
Updating 7b2e9c4..e5f6a7b
Fast-forward
src/savat.js | 84 ++++++++++++++++
src/savat.css | 31 ++++++
2 files changed, 115 insertions(+)
Keyin:
main
↓
●────●────●────●────●────●────●
↑
feature/savat
Tarix — to'g'ri chiziq. Yangi commit yaratilmadi.
2. Three-way merge — haqiqiy birlashtirish
Endi qiyinroq holat: ikkala branch da ham yangi commitlar bor.
main
↓
●────●────●────●────●────● (hamkasb: 2 commit)
↑ \
asos ●────●────● (siz: 3 commit)
↑
feature/savat
main ni shunchaki surib bo'lmaydi — hamkasbning commitlari yo'qolardi. Git uchta nuqtani solishtiradi (shuning uchun "3-way"):
- Asos (merge base) — ikki branch ajralgan umumiy commit
mainning oxirgi holatifeature/savatning oxirgi holati
va yangi merge commit yaratadi — ikkita ota-onaga ega:
git switch main
git merge feature/savat
Merge made by the 'ort' strategy.
src/savat.js | 84 ++++++++++++++++
src/savat.css | 31 ++++++
2 files changed, 115 insertions(+)
main
↓
●────●────●────●────●────●────◆ ← merge commit
\ /
●────●────●──
↑
feature/savat
Git muharrirni ochib, merge commit xabarini so'raydi — standart "Merge branch 'feature/savat'" odatda yetarli.
Git qanday qaror qiladi
Har bir fayl uchun, asosga nisbatan:
main |
feature |
Natija |
|---|---|---|
| O'zgarmagan | O'zgargan | feature versiyasi |
| O'zgargan | O'zgarmagan | main versiyasi |
| Turli qatorlar o'zgargan | Ikkalasi avtomatik qo'shiladi | |
| Bir xil qator turlicha o'zgargan | ⚠️ Conflict — siz hal qilasiz (16-dars) |
Ko'p hollarda — 90% dan ko'p — Git hammasini o'zi birlashtiradi.
Fast-forward yoki merge commit?
git merge --no-ff feature/savat # fast-forward mumkin bo'lsa ham, merge commit yaratish
git merge --ff-only feature/savat # faqat fast-forward; mumkin bo'lmasa — rad etish
| Fast-forward | Merge commit (--no-ff) |
|
|---|---|---|
| Tarix | To'g'ri chiziq, toza | Branch lar ko'rinadi |
| "Bu funksiya qaysi commitlardan iborat edi?" | Ko'rinmaydi | Aniq ko'rinadi |
| Butun funksiyani bekor qilish | Har commit ni alohida | Bitta merge commit ni revert (28-dars) |
--no-ff bilan:
●────●──────────────────◆──── main
\ /
●────●────●────● feature/savat — guruh sifatida ko'rinadi
Jamoalar turlicha tanlaydi. GitHub da PR ni birlashtirishda uchta variant bor (23-dars): Merge commit, Squash and merge (barcha commitlar bittaga), Rebase and merge (17-dars).
Squash merge
git merge --squash feature/savat
git commit -m "Savat funksiyasi qo'shildi"
feature/savat dagi barcha o'zgarishlar bitta yangi commit sifatida — "WIP", "fix typo" kabi oraliq commitlarsiz. Toza tarix, lekin oraliq tarix yo'qoladi.
Main ni feature ga qo'shish
Uzoq ishlayotgan feature branch main dan orqada qoldi. Yangi o'zgarishlarni olish uchun:
git switch feature/savat
git merge main
Endi feature/savat da main ning eng yangi kodi bor — conflict lar (bo'lsa) hozir, kichik bo'lganda hal qilinadi, oxirida emas. Muqobil — rebase (17-dars).
Merge ni bekor qilish
Merge conflict bilan to'xtadi va siz boshlashdan oldingi holatga qaytmoqchisiz:
git merge --abort
Merge muvaffaqiyatli tugadi, lekin xato edi (hali push qilinmagan):
git reset --hard HEAD~1 # ⚠️ 27-dars — avval tushuning
Push qilingan bo'lsa — git revert -m 1 <merge-hash> (28-dars).
Merge dan keyin
git log --oneline --graph -10 # natijani ko'rish
git branch -d feature/savat # branch endi kerak emas
git push # main ni GitHub ga
Nima uchun shunday?
Nima uchun Git ikki versiyani emas, uchtani solishtiradi — main va feature ni to'g'ridan-to'g'ri solishtirish yetmaydimi?
Chunki ikki versiyani solishtirib, kim o'zgartirganini bilib bo'lmaydi. main da narx = 100, feature da narx = 120 — qaysi biri yangi? Balki main 120 dan 100 ga o'zgartirgandir, balki feature 100 dan 120 ga. Asos (umumiy ajdod) bu savolga javob beradi: asosda narx = 100 bo'lsa — demak feature o'zgartirgan, main tegmagan → natija 120. Asos bo'lmasa, Git har bir farqni conflict deb e'lon qilishga majbur bo'lardi. Uchinchi nuqta — avtomatik birlashtirishni aqlli qiladigan narsa.
Xulosa
Eslab qoling:
- Qabul qiluvchi branch da turing:
git switch main→git merge feature - Fast-forward —
maino'zgarmagan bo'lsa, ko'rsatkich shunchaki suriladi; yangi commit yo'q - 3-way merge — ikkala tomonda o'zgarish; asos + ikki uch → merge commit (ikki ota)
- Turli qatorlar — avtomatik; bir xil qator — conflict
--no-ff— har doim merge commit;--ff-only— faqat fast-forward;--squash— bitta commitgit merge main(feature da) —maindagi yangiliklarni olishgit merge --abort— conflict da bekor qilish
Keyingi dars
16-dars: Merge Conflict — nima uchun chiqadi, qanday hal qilinadi