git merge — Fast-forward va 3-way merge, farqlari

~20 daq · Git · Branch va Merge

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"):

  1. Asos (merge base) — ikki branch ajralgan umumiy commit
  2. main ning oxirgi holati
  3. feature/savat ning 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 — main o'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 commit
  • git merge main (feature da) — main dagi yangiliklarni olish
  • git merge --abort — conflict da bekor qilish

Keyingi dars

16-dars: Merge Conflict — nima uchun chiqadi, qanday hal qilinadi