IlmHamroh
JavaScript Full-stack/7-qism. Git va GitHub asoslari17/36-dars24 daqiqa
Mundarija (37)

Git conflict: merge conflictlarni yechish amaliyoti

Qisqacha: Conflict — ikki branch bitta joyni turlicha o'zgartirganda Git sizdan qaror so'rashi. Faylda <<<<<<<, =======, >>>>>>> markerlari paydo bo'ladi. Ularni o'chirib, to'g'ri variantni qoldirasiz, keyin git add va git commit. Qo'rqsangiz — git merge --abort hammasini merge'dan oldingi holatga qaytaradi. merge.conflictStyle zdiff3 markerlar orasida asl versiyani ham ko'rsatadi.

Bu darsda

  • Conflict nega paydo bo'lishini va nega bu xato emasligini tushuntirasiz.
  • Conflict markerlarini o'qib, faylni qo'lda to'g'ri holatga keltirasiz.
  • zdiff3 uslubi, VS Code merge editor, --ours va --theirs bilan tezroq yechasiz.
  • git merge --abort bilan xavfsiz orqaga qaytasiz va rerere bilan takroriy conflictni avtomatlashtirasiz.
  • package-lock.json conflictini qo'lda tahrirlamasdan, npm yordamida yechasiz.

Oldin bilishingiz kerak: Merge: fast-forward va uch tomonlama birlashtirish, O'zgarishlarni ko'rish: git diff, Xatoni tuzatish 2: reset va revert.

1. Nega bu kerak?

Oldingi darsda uch tomonlama merge'ni ko'rdik: har bir bo'lakni kim o'zgartirganini Git o'zi aniqlaydi. Lekin bitta holatni ochiq qoldirgan edik: ikkala tomon bir joyni turlicha o'zgartirsa-chi?

«Bahor»da xuddi shunday bo'ldi. Jasur aka osh narxini 38 000 so'mga ko'tardi. Rustam aka esa o'sha qatorga "qazi bilan" degan tavsif qo'shdi. Ikkalasi ham to'g'ri ish qildi. Qaysi qator qolishi kerak? Git buni bilmaydi — bu biznes qarori, kod emas.

Shunday paytda Git to'xtaydi va sizdan so'raydi. Buni conflict (ziddiyat) deyiladi. Versiya nazorati darsida "Git bir odamning ishini jimgina o'chirib yubormaydi" degan edik. Conflict — o'sha va'daning amaldagi ko'rinishi.

Birinchi marta conflict ko'rgan boshlovchi qo'rqib ketadi: qizil yozuvlar, g'alati belgilar. Aslida hech narsa buzilmagan va hech narsa yo'qolmagan. Bu dars conflict'ni tartib bilan, xotirjam yechishni o'rgatadi.

2. Conflict'ni yaratamiz

2.1 Ikki kishi — bir qator

Menyu fayli hozir shunday:

bash
cd ~/kurs/bahor
cat menyu/index.html
text
<h1>Menyu</h1>
<p>Osh — 35 000 so'm</p>
<p>Lag'mon — 28 000 so'm</p>
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

Jasur aka fix/osh-narxi branch'ida narxni o'zgartirdi, Rustam aka feature/osh-tavsif da tavsif qo'shdi. Ikkala branch ham main ning bir nuqtasidan ochilgan. Buni o'zingiz takrorlang: har branch'da menyu/index.html ning osh qatorini VS Code'da tahrirlab, commit qiling.

bash
git switch -c fix/osh-narxi
# osh qatori: 35 000 → 38 000
git commit -am "Menyu: osh narxini 38 000 qil"
git switch main
git switch -c feature/osh-tavsif
# osh qatori: oxiriga " (qazi bilan)"
git commit -am "Menyu: oshga tavsif qo'sh"
git switch main
text
[fix/osh-narxi 4607992] Menyu: osh narxini 38 000 qil
 1 file changed, 1 insertion(+), 1 deletion(-)
[feature/osh-tavsif 46f80bf] Menyu: oshga tavsif qo'sh
 1 file changed, 1 insertion(+), 1 deletion(-)

-am — Birinchi repo darsidagi -a va -m birga: fayl allaqachon kuzatilayotgani uchun bu yerda xavfsiz. (git switch xabarlarini qisqartirdik.)

Jasur akaning ishi birinchi qo'shiladi. main shu orada yurmagan — fast-forward:

bash
git merge fix/osh-narxi
text
Updating 076bc39..4607992
Fast-forward
 menyu/index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

2.2 Conflict

Endi Rustam akaning navbati:

bash
git merge feature/osh-tavsif
text
Auto-merging menyu/index.html
CONFLICT (content): Merge conflict in menyu/index.html
Automatic merge failed; fix conflicts and then commit the result.

Tarjimasi:

  • Auto-merging menyu/index.html — "menyu/index.html avtomatik birlashtirilmoqda".
  • CONFLICT (content): Merge conflict in menyu/index.html — "ZIDDIYAT (mazmunda): menyu/index.html da merge ziddiyati".
  • Automatic merge failed; fix conflicts and then commit the result. — "Avtomatik merge muvaffaqiyatsiz; ziddiyatlarni tuzating, keyin natijani commit qiling".

Git vazifani yarim yo'lda to'xtatdi va keyingi qadamni aniq aytdi. Merge tugamadi — u siz bilan davom etishni kutyapti.

3. Conflict'ni o'qish

3.1 git status

Birinchi qadam doim bir xil:

bash
git status
text
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (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")

Tarjimasi: "Birlashtirilmagan yo'llaringiz bor (ziddiyatlarni tuzatib, git commit qiling; merge'ni bekor qilish uchun git merge --abort). Birlashtirilmagan yo'llar (hal qilinganini belgilash uchun git add): ikkala tomonda o'zgargan: menyu/index.html".

Uchta muhim ma'lumot: qaysi fayl muammoli (both modified), qanday tugatish (git add → git commit) va qanday qochish (git merge --abort). Qisqa formatda:

bash
git status -s
text
UU menyu/index.html

UU — "unmerged, ikkala tomonda o'zgargan". Conflictli fayllar ko'p bo'lsa, ro'yxatni shu belgilar bo'yicha ko'rish qulay.

3.2 Markerlar

Faylning o'zini ochamiz:

bash
cat menyu/index.html
text
<h1>Menyu</h1>
<<<<<<< HEAD
<p>Osh — 38 000 so'm</p>
=======
<p>Osh — 35 000 so'm (qazi bilan)</p>
>>>>>>> feature/osh-tavsif
<p>Lag'mon — 28 000 so'm</p>
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

Git conflictli joyni uch marker bilan o'rab qo'ydi:

Marker Ma'nosi
<<<<<<< HEAD Bu yerdan — siz turgan branch'dagi variant (main)
======= Ajratgich: tepasi — sizniki, pasti — qo'shilayotgan branch'niki
>>>>>>> feature/osh-tavsif Shu yergacha — qo'shilayotgan branch varianti

Fayldagi qolgan qatorlarga (<h1>, lag'mon, somsa) Git tegmadi — ular ziddiyatsiz birlashdi. Muammo faqat markerlar ichida.

flowchart TD
  A["git merge"] --> B{"Conflict?"}
  B -- yo'q --> C["Merge tayyor"]
  B -- ha --> D["git status: qaysi fayl?"]
  D --> E["Faylni tahrirlash:<br/>markerlarni olib tashlash"]
  E --> F["git add fayl"]
  F --> G["git commit"]
  D -. qo'rqsangiz .-> H["git merge --abort"]

Nimaga qarang: conflict — merge'ning bitta qo'shimcha bosqichi, xolos. Asosiy yo'l to'rt qadam. Istalgan paytda punktir yo'l bilan boshiga qaytish mumkin.

3.3 git diff conflict paytida

O'zgarishlarni ko'rish darsidagi git diff conflict paytida alohida ko'rinishda chiqadi:

bash
git diff
text
diff --cc menyu/index.html
index 2f22afc,e90c575..0000000
--- a/menyu/index.html
+++ b/menyu/index.html
@@@ -1,5 -1,5 +1,9 @@@
  <h1>Menyu</h1>
++<<<<<<< HEAD
 +<p>Osh — 38 000 so'm</p>
++=======
+ <p>Osh — 35 000 so'm (qazi bilan)</p>
++>>>>>>> feature/osh-tavsif
  <p>Lag'mon — 28 000 so'm</p>
  <p>Somsa — 8 000 so'm</p>
  <p>Shashlik — 15 000 so'm</p>

diff --cc — "birlashgan diff": har qatorning boshida bitta emas, ikkita ustun bor. Birinchi ustun — main ga nisbatan, ikkinchisi — feature/osh-tavsif ga nisbatan. Masalan, +<p>Osh — 38 000 — "ikkinchi tomonda bu qator yo'q edi". Bu ko'rinishni o'qish shart emas — fayldagi markerlar yetarli. Lekin uni ko'rganda "nega ikkita plyus?" deb hayron bo'lmaysiz.

Tekshirib ko'ring: Markerlar orasidagi qaysi qator main dan, qaysi biri feature/osh-tavsif dan keldi? Qanday bildingiz?

Javob

<<<<<<< HEAD va ======= orasidagi 38 000 qatori — main dan, chunki HEAD siz turgan branch, biz esa main da merge boshladik. ======= va >>>>>>> feature/osh-tavsif orasidagi "qazi bilan" qatori — qo'shilayotgan branch'dan: uning nomi pastki markerda yozilgan.

4. Qo'lda yechish

4.1 Tugatmasdan harakat qilsak

Avval ikki "noto'g'ri" urinish — ularning xabarlarini tanib olish uchun. Conflict yechilmay turib commit:

bash
git commit -m "Merge"
text
error: Committing is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
U	menyu/index.html

Tarjimasi: "Commit qilib bo'lmaydi — birlashtirilmagan fayllar bor. Ularni ishchi papkada tuzating, keyin git add/rm <fayl> bilan hal qilinganini belgilab, commit qiling. Hal qilinmagan ziddiyat sababli chiqildi". Git yarim tayyor faylni tarixga yozishga yo'l qo'ymaydi.

Boshqa branch'ga qochish ham ishlamaydi:

bash
git switch feature/osh-tavsif
text
fatal: cannot switch branch while merging
Consider "git merge --quit" or "git worktree add".

"Merge paytida branch almashtirib bo'lmaydi". Merge'ni yo tugatish, yo bekor qilish kerak.

4.2 Qaror va tahrir

Endi qaror qabul qilamiz. Jasur aka va Rustam aka bilan gaplashdik: narx ham yangi, tavsif ham kerak. To'g'ri qator — ikkalasining birikmasi. VS Code'da faylni ochib, markerlarni ham, eski variantlarni ham o'chiramiz va bitta to'g'ri qator qoldiramiz:

bash
cat menyu/index.html
text
<h1>Menyu</h1>
<p>Osh — 38 000 so'm (qazi bilan)</p>
<p>Lag'mon — 28 000 so'm</p>
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

Qoida oddiy: fayl conflict'dan keyin qanday bo'lishi kerak bo'lsa, xuddi shunday yozing. Bu ikki variantdan biri bo'lishi mumkin, ikkalasining birikmasi yoki butunlay yangi qator. Git'ga faqat natija kerak.

4.3 git add — "hal qildim"

Conflict paytida git add ning ma'nosi biroz boshqacha: "bu fayldagi ziddiyat hal qilindi":

bash
git add menyu/index.html
git status
text
On branch main
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
	modified:   menyu/index.html

"Hamma ziddiyatlar tuzatildi, lekin siz hali merge jarayonidasiz (merge'ni yakunlash uchun git commit)".

4.4 Yakunlash

bash
git commit

VS Code'da xabar tabi ochiladi. Biz uning mazmunini ekranga chiqardik:

text
Merge branch 'feature/osh-tavsif'

# Conflicts:
#	menyu/index.html
#
# It looks like you may be committing a merge.
# If this is not correct, please run
#	git update-ref -d MERGE_HEAD
# and try again.


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch main
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
#	modified:   menyu/index.html
#

Tayyor xabar Merge branch 'feature/osh-tavsif', ostida esa izoh ichida conflictli fayllar ro'yxati. Jamoalarda ba'zan xabarga bir qator qo'shiladi: qanday qaror qabul qilinganini aytish uchun (masalan, "Osh: narx Jasurdan, tavsif Rustamdan"). Tabni yopamiz:

text
[main 2d78c9c] Merge branch 'feature/osh-tavsif'
bash
git log --oneline --graph -6
text
*   2d78c9c (HEAD -> main) Merge branch 'feature/osh-tavsif'
|\  
| * 46f80bf (feature/osh-tavsif) Menyu: oshga tavsif qo'sh
* | 4607992 (fix/osh-narxi) Menyu: osh narxini 38 000 qil
|/  
* 076bc39 Aloqa: telefon raqamini qo'sh
...
gitGraph
  commit id: "076bc39 telefon"
  branch feature/osh-tavsif
  commit id: "46f80bf tavsif"
  checkout main
  commit id: "4607992 38 000"
  merge feature/osh-tavsif id: "2d78c9c merge"

Nimaga qarang: conflict bilan yechilgan merge'ning shakli oddiy merge'dan farq qilmaydi — ikki otali commit. Conflict tarixda iz qoldirmaydi, faqat merge commit ichidagi fayl sizning qaroringizni saqlaydi.

Ikkala branch ham ishini berdi — o'chiramiz:

bash
git branch -d fix/osh-narxi feature/osh-tavsif
text
Deleted branch fix/osh-narxi (was 4607992).
Deleted branch feature/osh-tavsif (was 46f80bf).

5. zdiff3: asl versiyani ham ko'rish

5.1 Muammo

Oddiy markerlar ikkita variantni ko'rsatadi, lekin asl holatni ko'rsatmaydi. Oshda bu oson edi. Murakkab qatorlarda esa savol tug'iladi: bu tomonda nima o'zgardi? Javob uchun ajralishdan oldingi versiya — merge base kerak.

5.2 Sozlash

Git'ga markerlar ichida uchinchi bo'lakni ham ko'rsatishni aytamiz:

bash
git config --global merge.conflictStyle zdiff3

zdiff3 — "zealous diff3": asl versiyani ham ko'rsatadi va ikkala tomonda bir xil bo'lgan qatorlarni markerlardan tashqariga chiqaradi. Git 2.35 dan beri bor.

Endi lag'mon uchun yangi conflict yasaymiz: fix/lagmon-narxi da narx 30 000 bo'ldi, main da esa "qo'l lag'mon" tavsifi qo'shildi. Merge:

bash
git merge fix/lagmon-narxi
cat menyu/index.html
text
Auto-merging menyu/index.html
CONFLICT (content): Merge conflict in menyu/index.html
Automatic merge failed; fix conflicts and then commit the result.
<h1>Menyu</h1>
<p>Osh — 38 000 so'm (qazi bilan)</p>
<<<<<<< HEAD
<p>Lag'mon — 28 000 so'm (qo'l lag'mon)</p>
||||||| 2d78c9c
<p>Lag'mon — 28 000 so'm</p>
=======
<p>Lag'mon — 30 000 so'm</p>
>>>>>>> fix/lagmon-narxi
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

Yangi marker — |||||||. Undan keyin — merge base'dagi (2d78c9c) asl qator. Endi ikkala tomonning nima qilgani aniq ko'rinadi:

  • main (HEAD): asl qatorga "(qo'l lag'mon)" qo'shgan, narxga tegmagan.
  • fix/lagmon-narxi: narxni 28 000 dan 30 000 ga o'zgartirgan, tavsif qo'shmagan.

Demak to'g'ri javob — ikkala o'zgarishni ham olish: Lag'mon — 30 000 so'm (qo'l lag'mon). Asl versiyasiz buni taxmin qilishga to'g'ri kelardi.

Maslahat: zdiff3 ni bir marta global sozlang va unuting. Tajribali dasturchilarning ko'pchiligi shuni tavsiya qiladi. Bu darsning qolgan misollari shu uslubda.

6. Orqaga yo'l: git merge --abort

Ba'zan conflict kutilganidan katta chiqadi yoki qaror qabul qilish uchun hamkasbingizni kutish kerak. Merge'ni butunlay bekor qilamiz:

bash
git merge --abort
git status
cat menyu/index.html
text
On branch main
nothing to commit, working tree clean
<h1>Menyu</h1>
<p>Osh — 38 000 so'm (qazi bilan)</p>
<p>Lag'mon — 28 000 so'm (qo'l lag'mon)</p>
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

Hammasi merge'dan oldingi holatda: markerlar yo'q, main o'zgarmagan, fix/lagmon-narxi joyida. Istalgan paytda merge'ni qayta boshlash mumkin.

--abort — sizning xavfsizlik tugmangiz. Faqat bitta shart: merge boshlanishidan oldin ishchi papka toza bo'lsin (Merge darsidagi odat). Aks holda Git commit qilinmagan o'zgarishlaringizni to'g'ri tiklay olmasligi mumkin.

Tekshirib ko'ring: git merge --abort dan keyin fix/lagmon-narxi branch'idagi commit yo'qoladimi?

Javob

Yo'q. --abort faqat joriy branch'ni va ishchi papkani merge'dan oldingi holatga qaytaradi. Qo'shilayotgan branch'ga umuman tegmaydi — uning commitlari joyida.

7. Butun faylni tanlash: --ours va --theirs

Ba'zan qaror oddiy: "butun faylni bir tomondan ol". Masalan, avtomatik yaratilgan fayllarda yoki bir tomonning ishi aniq eskirgan bo'lsa. Merge'ni qayta boshlaymiz va --theirs ni sinaymiz:

bash
git merge fix/lagmon-narxi
git checkout --theirs menyu/index.html
cat menyu/index.html
text
Auto-merging menyu/index.html
CONFLICT (content): Merge conflict in menyu/index.html
Automatic merge failed; fix conflicts and then commit the result.
Updated 1 path from the index
<h1>Menyu</h1>
<p>Osh — 38 000 so'm (qazi bilan)</p>
<p>Lag'mon — 30 000 so'm</p>
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

--theirs — "ularniki", qo'shilayotgan branch'ning versiyasi. Updated 1 path from the index — "1 ta yo'l indeksdan yangilandi". Conflict paytida staging area (Uch hudud) faylning uchala versiyasini ham saqlaydi. Git kerakligini o'sha yerdan oldi.

Teskarisi — --ours, "bizniki", siz turgan branch:

bash
git checkout --ours menyu/index.html
cat menyu/index.html
text
Updated 1 path from the index
<h1>Menyu</h1>
<p>Osh — 38 000 so'm (qazi bilan)</p>
<p>Lag'mon — 28 000 so'm (qo'l lag'mon)</p>
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

Fikringizdan qaytib, markerlarni qaytarmoqchi bo'lsangiz — --merge:

bash
git checkout --merge menyu/index.html
cat menyu/index.html
text
Recreated 1 merge conflict
<h1>Menyu</h1>
<p>Osh — 38 000 so'm (qazi bilan)</p>
<<<<<<< ours
<p>Lag'mon — 28 000 so'm (qo'l lag'mon)</p>
||||||| base
<p>Lag'mon — 28 000 so'm</p>
=======
<p>Lag'mon — 30 000 so'm</p>
>>>>>>> theirs
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

"1 ta merge ziddiyati qayta yaratildi". Bu safar markerlarda ours, base, theirs so'zlari — bu ham zdiff3 ko'rinishi, faqat nomlar boshqacha.

Diqqat: --ours/--theirs butun faylni bir tomondan oladi va ikkinchi tomonning shu fayldagi hamma o'zgarishini tashlaydi — conflictsiz birlashgan qismlarini ham. Ishlatishdan oldin nima yo'qolishini o'ylang. Rebase darsida bu ikki so'z ma'nosi teskari bo'lib ketishini ham ko'rasiz.

Tajribani tugatamiz: git merge --abort.

8. VS Code merge editor

Terminalda markerlarni qo'lda o'chirish ishlaydi, lekin VS Code buni ancha qulay qiladi. Conflictli faylni ochsangiz, har conflict ustida kichik tugmalar paydo bo'ladi:

  • Accept Current Change — "joriy o'zgarishni qabul qilish" (HEAD, siz turgan branch).
  • Accept Incoming Change — "kelayotgan o'zgarishni qabul qilish" (qo'shilayotgan branch).
  • Accept Both Changes — ikkalasini ham, ketma-ket.
  • Compare Changes — ikki variantni yonma-yon solishtirish.

Source Control panelida conflictli fayl Merge Changes bo'limida ! belgisi bilan turadi. Faylni ochganda pastki o'ng burchakda Resolve in Merge Editor tugmasi chiqadi. U uch oynali muharrirni ochadi: tepada ikki tomon (Incoming va Current), pastda — natija (Result). Kerakli bo'laklarni belgilaysiz, natijani tekshirasiz va Complete Merge tugmasini bosasiz. Bu tugma git add ishini qiladi. Keyin Source Control'da commit qilasiz.

Qaysi yo'l bilan yechsangiz ham, mantiq bir xil: to'g'ri natijani yozish, add, commit. VS Code — faqat qulay qalam.

9. rerere: bir xil conflict'ni ikki marta yechmaslik

Ba'zan bitta conflict'ni qayta-qayta yechishga to'g'ri keladi. Masalan, merge'ni bekor qilib qayta qilganda yoki Rebase paytida. Git bunday qarorlarni eslab qolishi mumkin. Funksiya nomi — rerere (reuse recorded resolution — "yozib olingan yechimni qayta ishlatish"):

bash
git config --global rerere.enabled true

Sinaymiz. Lag'mon conflict'ini yana boshlaymiz:

bash
git merge fix/lagmon-narxi
text
Auto-merging menyu/index.html
CONFLICT (content): Merge conflict in menyu/index.html
Recorded preimage for 'menyu/index.html'
Automatic merge failed; fix conflicts and then commit the result.

Yangi qator: Recorded preimage — "conflict ko'rinishi yozib olindi". Endi «zdiff3» bo'limida topgan qarorimizni yozamiz: Lag'mon — 30 000 so'm (qo'l lag'mon). Keyin:

bash
git add menyu/index.html
git commit --no-edit
text
Recorded resolution for 'menyu/index.html'.
[main 7658a99] Merge branch 'fix/lagmon-narxi'

"menyu/index.html uchun yechim yozib olindi". --no-edit — muharrirni ochmasdan, tayyor xabar bilan commit.

Endi merge'ni ataylab bekor qilamiz — reset bilan oxirgi commitni olib tashlaymiz va qayta merge qilamiz:

bash
git reset --hard HEAD~1
git merge fix/lagmon-narxi
cat menyu/index.html
text
HEAD is now at d74017e Menyu: lag'monga tavsif qo'sh
Auto-merging menyu/index.html
CONFLICT (content): Merge conflict in menyu/index.html
Resolved 'menyu/index.html' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
<h1>Menyu</h1>
<p>Osh — 38 000 so'm (qazi bilan)</p>
<p>Lag'mon — 30 000 so'm (qo'l lag'mon)</p>
<p>Somsa — 8 000 so'm</p>
<p>Shashlik — 15 000 so'm</p>

Resolved 'menyu/index.html' using previous resolution. — "oldingi yechim bilan hal qilindi". Faylda markerlar yo'q — bizning qarorimiz turibdi. Lekin Git baribir "merge failed" deydi: u yechimni qo'ydi, ammo tekshirish va git add ni sizga qoldirdi. Tekshirib, yakunlaymiz:

bash
git add menyu/index.html
git commit --no-edit
git branch -d fix/lagmon-narxi

Bugungi darsda rerere ning foydasi kichik ko'rinadi. Rebase va uzoq yashaydigan branch'larda esa u soatlab vaqt tejaydi. Bundan keyin Recorded preimage qatorlarini ko'rsangiz — bu shu sozlamaning ishi.

10. package-lock.json conflicti

10.1 Qanday paydo bo'ladi

Siz npm bilan tanishsiz: package.json — loyiha qaysi paketlarga bog'liqligi ro'yxati, package-lock.json — o'rnatilgan aniq versiyalar. Ikkala faylni npm o'zi yozadi (npm'ni kursda alohida chuqur o'rganamiz). Ikki branch'da ikki xil paket o'rnatilsa, bu ikki fayl deyarli har doim conflict beradi.

sinov-git/paketlar repoda sinab ko'rdik: bir branch'da ms paketi o'rnatildi, ikkinchisida nanoid. Birinchisi main ga qo'shilgan, ikkinchisini qo'shamiz:

bash
git merge feature/id-yasash
git status -s
text
Auto-merging package-lock.json
CONFLICT (content): Merge conflict in package-lock.json
Auto-merging package.json
CONFLICT (content): Merge conflict in package.json
Recorded preimage for 'package-lock.json'
Recorded preimage for 'package.json'
Automatic merge failed; fix conflicts and then commit the result.
UU package-lock.json
UU package.json

package.json qisqa — uni oddiy fayl kabi o'qiymiz:

bash
cat package.json
text
{
  "name": "paketlar",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
<<<<<<< HEAD
    "ms": "^2.1.3"
||||||| b454a21
  "private": true
=======
    "nanoid": "^3.3.11"
>>>>>>> feature/id-yasash
  }
}

Asl versiyada dependencies bo'limi umuman yo'q edi, shuning uchun ||||||| ostida Git eng yaqin mos qatorni ko'rsatdi. Mazmuni aniq: bir tomon ms ni, ikkinchisi nanoid ni qo'shgan. Ikkalasi ham kerak.

10.2 To'g'ri yo'l

package-lock.json esa yuzlab qatorli va uni qo'lda tahrirlash — xatoga yo'l. Rasmiy npm hujjatidagi tavsiya: avval package.json dagi conflict'ni qo'lda yeching, keyin npm install ni ishga tushiring. Shunda npm lock fayldagi markerlarni o'zi hal qilib, ikkala tomonning paketlarini birlashtirgan yangi lock yozadi.

package.json ni to'g'rilaymiz — ikkala qator, orasida vergul:

json
{
  "name": "paketlar",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "ms": "^2.1.3",
    "nanoid": "^3.3.11"
  }
}

Keyin lock faylga tegmasdan:

bash
grep -c '<<<<<<<' package-lock.json
npm install
grep -c '<<<<<<<' package-lock.json
text
1

added 1 package in 1s
0

grep -c — mos qatorlar soni (Fayl qidirish darsidan). Oldin lock faylda 1 ta conflict bor edi, npm install dan keyin — 0. Vaqt sizda boshqacha bo'ladi. Biz npm install ni --no-fund --no-audit bilan ishga tushirdik — homiylik va xavfsizlik tekshiruvi haqidagi qo'shimcha qatorlar chiqmasligi uchun. Endi ikkala faylni "hal qilindi" deb belgilaymiz:

bash
git add package.json package-lock.json
git status -s
text
M  package-lock.json
M  package.json

Qolgani — oddiy git commit.

Diqqat: package-lock.json da git checkout --ours yoki --theirs bilan bir tomonni tanlab qo'ya qolmang. Shunda ikkinchi tomonning paketi lock'dan tushib qoladi va package.json bilan mos kelmaydi. To'g'ri tartib: package.json → npm install → git add.

11. Ko'p uchraydigan xatolar

11.1 Unutilgan marker

Eng xavfli xato — markerni o'chirishni unutib, faylni git add qilish. Git bunga to'sqinlik qilmaydi: add — "men hal qildim" degani, u sizga ishonadi. Natijada <<<<<<< saytga chiqib ketadi. Commitdan oldin tekshiruv:

bash
git diff --cached --check
text
bron/index.html:7: leftover conflict marker
bron/index.html:9: leftover conflict marker
bron/index.html:11: leftover conflict marker

Tarjimasi: "bron/index.html ning 7-, 9-, 11-qatorlarida qolib ketgan conflict markeri". --check staging'dagi o'zgarishlarda shunday qoldiqlarni izlaydi. Hech narsa chiqmasa — toza. Tuzatish: faylni ochib, markerlarni olib tashlang, qayta git add.

11.2 "O'chirildi" va "o'zgartirildi"

Conflict faqat mazmunda emas. Bir branch'da fayl o'chirilgan, ikkinchisida o'zgartirilgan bo'lsa:

text
CONFLICT (modify/delete): bron/rahmat.html deleted in chore/tozalash and modified in HEAD.  Version HEAD of bron/rahmat.html left in tree.
Automatic merge failed; fix conflicts and then commit the result.

Tarjimasi: "ZIDDIYAT (o'zgartirish/o'chirish): bron/rahmat.html chore/tozalash da o'chirilgan, HEAD'da o'zgartirilgan. Faylning HEAD versiyasi ishchi papkada qoldirildi". git status -s bu faylni UD deb ko'rsatadi ("biz o'zgartirdik, ular o'chirdi"). Markerlar yo'q — savol bitta: fayl kerakmi? Kerak bo'lsa — git add bron/rahmat.html, kerak bo'lmasa — git rm bron/rahmat.html. Keyin git commit.

11.3 Conflict'dan qo'rqib, papkani o'chirish

Boshlovchi ba'zan vahimaga tushib, loyihani qaytadan yuklab oladi yoki .git ni o'chiradi. Hech qachon! Doim ikki xavfsiz yo'l bor: yechish yoki git merge --abort.

11.4 Faqat o'zinikini qoldirish

Tez tugatish uchun har conflict'da "Accept Current Change" ni bosish — hamkasbingizning ishini jimgina o'chirish demak. Git aynan shundan himoya qilmoqchi edi. Ikkinchi tomon nima qilganini tushunmasangiz — zdiff3 dagi asl versiyaga qarang yoki o'sha odamdan so'rang.

12. Mashqlar

1-mashq (oson): Markerlarni o'qing

Siz main da turib git merge fix/narx qildingiz va shuni ko'rdingiz:

text
<<<<<<< HEAD
<p>Choy — 5 000 so'm</p>
||||||| 665b8e5
<p>Choy — 4 000 so'm</p>
=======
<p>Ko'k choy — 4 000 so'm</p>
>>>>>>> fix/narx

(||||||| dan keyingi 665b8e5 — umumiy ajdod commitning qisqa SHA'si; sizda u boshqacha bo'ladi.)

  1. Qaysi branch narxni o'zgartirgan?
  2. Qaysi branch nomni o'zgartirgan?
  3. To'g'ri yechim qanday qator?
Yechim

Asl qator (||||||| ostida): Choy — 4 000 so'm.

  1. main (HEAD): narx 4 000 → 5 000, nom o'sha-o'sha.
  2. fix/narx: nom "Choy" → "Ko'k choy", narx o'sha-o'sha.
  3. Ikkala o'zgarish birga: <p>Ko'k choy — 5 000 so'm</p>. Asl versiya bo'lmasa, qaysi tomon nimani o'zgartirganini aniqlash qiyin edi.

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

Conflict'ni yechish ketma-ketligi:

bash
git merge feature/menyu
# CONFLICT (content): Merge conflict in menyu/index.html
git 
# VS Code'da markerlarni olib tashlaymiz
git diff --cached --check
git  menyu/index.html
git 

Merge'ni butunlay bekor qilish uchun esa: git merge .

Ishora: qaysi fayl muammoli — «Conflict'ni o'qish» bo'limi; "hal qildim" belgisi — «Qo'lda yechish».

Yechim
bash
git merge feature/menyu
git status
git diff --cached --check
git add menyu/index.html
git commit

E'tibor bering: git diff --cached --check bu tartibda hali hech narsa ko'rsatmaydi — fayl hali add qilinmagan. Uni git add dan keyin, commitdan oldin ishlatish kerak. Bekor qilish — git merge --abort.

3-mashq (qiyin): O'z conflict'ingizni yarating

Bu safar conflict'ni boshidan oxirigacha o'zingiz yaratasiz va yechasiz. Ish mashqlar reposida, 07/17-conflict/ papkasida bo'ladi (Yaxshi commit darsida ochgan repo). Commit xabarlari shu repo kelishuvi bo'yicha 07/17: bilan boshlanadi.

  1. 07/17-conflict/narxlar.txt faylida uch qator: non 4000, choy 5000, somsa 8000. Commit qiling.
  2. fix/non branch'ida non 4000 ni non 4500 ga o'zgartirib commit qiling.
  3. main ga qaytib, xuddi shu qatorni non 5000 qiling va commit qiling.
  4. git merge fix/non — conflict. zdiff3 sozlangan bo'lsa, asl qatorni ham ko'rasiz.
  5. Qaror: non 5000. Yeching, yakunlang va fix/non ni o'chiring.
  6. Savol (faqat o'ylang, bajarish shart emas): choy qatorini ham ikkala tomonda o'zgartirsangiz, bitta faylda nechta conflict bo'lagi chiqadi?
Yechim
bash
cd ~/kurs/mashqlar
mkdir -p 07/17-conflict
cd 07/17-conflict
echo 'non 4000' > narxlar.txt
echo 'choy 5000' >> narxlar.txt
echo 'somsa 8000' >> narxlar.txt
git add narxlar.txt
git commit -m "07/17: narxlarni qo'sh"
git switch -c fix/non
# VS Code'da: non 4000 → non 4500, saqlang
git commit -am "07/17: non narxini 4500 qil"
git switch main
# VS Code'da: non 4000 → non 5000, saqlang
git commit -am "07/17: non narxini 5000 qil"
git merge fix/non

Windows'da add va commitlarda CRLF ogohlantirishi chiqishi mumkin — mashqlar reposida .gitattributes yo'q. Biz aynan shu qadamlarni bajardik. Faylda:

text
<<<<<<< HEAD
non 5000
||||||| b807e5a
non 4000
=======
non 4500
>>>>>>> fix/non
choy 5000
somsa 8000

b807e5a — umumiy commitning qisqa SHA'si, sizda boshqacha bo'ladi. Markerlar va non 4500 qatorini o'chirasiz, non 5000 qoladi. Keyin yakunlaymiz:

bash
git add narxlar.txt
git commit --no-edit
git branch -d fix/non
git log --oneline --graph -5
text
Recorded resolution for '07/17-conflict/narxlar.txt'.
[main 5060847] Merge branch 'fix/non'
Deleted branch fix/non (was 7710c85).
*   5060847 (HEAD -> main) Merge branch 'fix/non'
|\  
| * 7710c85 07/17: non narxini 4500 qil
* | 2b89e54 07/17: non narxini 5000 qil
|/  
* b807e5a 07/17: narxlarni qo'sh
* 90a9211 Mashqlar: 05 va 06-qism mashqlarini qo'sh

Birinchi qator — rerere ishi: u bu yechimni ham eslab qoldi. Eng pastki commit sizda boshqacha — mashqlar tarixingizda oldingi darslarning commitlari ham bor.

6-savol: qo'shni qatorlar (non va choy) ikkala tomonda o'zgarsa, Git ularni bitta conflict bo'lagiga birlashtiradi — orada o'zgarmagan qator yo'q. Buni alohida, tashlab yuboriladigan repoda sinab ko'rdik: markerlar orasida ikkala qator birga turdi. Agar o'zgargan qatorlar orasida kamida bitta o'zgarmagan qator bo'lsa, bo'laklar alohida chiqadi.

4-mashq: Portfolio qadami — birinchi haqiqiy conflict

Portfolio'da conflict'ni ataylab yaratib, VS Code merge editor bilan yechamiz. Footer'dagi mualliflik qatori ikki branch'da turlicha o'zgaradi.

  1. zdiff3 va rerere ni global sozlang (agar hali sozlamagan bo'lsangiz).
  2. main da footer qatoriga qarang (masalan, <footer>© 2026 Aziz</footer>).
  3. feature/footer-ism branch'ida ismni to'liq yozing: © 2026 Aziz Karimov. Commit: Footer: to'liq ismni yoz.
  4. main ga qayting va shu qatorga shaharni qo'shing: © 2026 Aziz · Toshkent. Commit: Footer: shaharni qo'sh.
  5. git merge feature/footer-ism — conflict.
  6. VS Code'da faylni oching, Resolve in Merge Editor orqali ikkala o'zgarishni oling: © 2026 Aziz Karimov · Toshkent. Complete Merge va commit.
  7. Branch'ni o'chiring, git log --oneline --graph -5 bilan tekshiring.
Yechim
bash
git config --global merge.conflictStyle zdiff3
git config --global rerere.enabled true
cd ~/kurs/portfolio
git switch -c feature/footer-ism
# footer: © 2026 Aziz Karimov
git commit -am "Footer: to'liq ismni yoz"
git switch main
# footer: © 2026 Aziz · Toshkent
git commit -am "Footer: shaharni qo'sh"
git merge feature/footer-ism

Qisqa sinov portfolio'sida (bosh sahifada faqat footer qatori bor) conflict shunday ko'rindi:

text
<!DOCTYPE html>
<<<<<<< HEAD
<footer>© 2026 Aziz · Toshkent</footer>
||||||| 6ae30fa
<footer>© 2026 Aziz</footer>
=======
<footer>© 2026 Aziz Karimov</footer>
>>>>>>> feature/footer-ism

Asl qatorga qarab ko'ramiz: main shahar qo'shgan, branch — familiya. Natija: <footer>© 2026 Aziz Karimov · Toshkent</footer>. Yechgach:

bash
git add sayt/index.html
git commit --no-edit
git branch -d feature/footer-ism
git log --oneline --graph -5
text
Recorded resolution for 'sayt/index.html'.
[main 868a51c] Merge branch 'feature/footer-ism'
Deleted branch feature/footer-ism (was 22bb65d).
*   868a51c (HEAD -> main) Merge branch 'feature/footer-ism'
|\  
| * 22bb65d Footer: to'liq ismni yoz
* | dfcc3ec Footer: shaharni qo'sh
|/  
* 6ae30fa Bosh sahifa: footer qo'sh
...

VS Code'da Complete Merge bossangiz, git add ni u qiladi — terminalda faqat commit qoladi. Footer'ingizdagi haqiqiy matn boshqacha bo'lsa, xuddi shu mantiq bilan ishlang: ikki tomonning o'zgarishini asl qator bilan solishtiring.

13. Real ishda

  • Conflict — kundalik ish. Jamoada har hafta bir necha conflict yechiladi. Tajribali dasturchi ham ulardan qochmaydi — faqat kichik va tez-tez merge qilib, ularni kichik saqlaydi.
  • Kichik branch — kichik conflict. Bir hafta yashagan branch — o'nlab conflict. Bir kun yashagan — bitta-ikkita. Shuning uchun main dagi yangiliklarni o'z branch'ingizga muntazam olib turish odat bo'ladi.
  • Lock fayllar. package-lock.json, pnpm-lock.yaml, yarn.lock conflictlari eng ko'p uchraydi. Qoida hamma joyda bir: manifest faylni yechish → paket menejerini ishga tushirish.
  • Intervyuda so'raladi: "Merge conflict'ni qanday yechasiz?" Yaxshi javob tartibni aytadi: git status → markerlarni o'qish → ikki tomon niyatini tushunish → tahrir → git add → commit, kerak bo'lsa --abort.

Xulosa

  • Conflict — ikki branch bir joyni turlicha o'zgartirganda Git sizdan qaror so'rashi; xato emas, hech narsa yo'qolmaydi.
  • <<<<<<< HEAD — siz turgan branch, >>>>>>> nom — qo'shilayotgan branch; zdiff3 bilan ||||||| ostida asl versiya ham ko'rinadi.
  • Yechish: faylni to'g'ri holatga keltirish → git add → git commit; qochish: git merge --abort.
  • --ours/--theirs butun faylni bir tomondan oladi; VS Code merge editor — qulay vizual yo'l.
  • rerere bir marta topilgan yechimni eslab, keyingi safar o'zi qo'yadi.
  • package-lock.json: avval package.json, keyin npm install; commitdan oldin git diff --cached --check.

Keyingi dars: Rebase: tarixni chiziqlash va oltin qoida — merge'ga muqobil yo'l: commitlarni yangi asosga ko'chirish va buni qachon qilmaslik kerakligi.

Manbalar

  • Pro Git kitobi: "Basic Merge Conflicts", "Advanced Merging" va "Rerere" — git-scm.com/book
  • Git hujjati: "git-merge" (HOW CONFLICTS ARE PRESENTED), "git-rerere", merge.conflictStyle — git-scm.com/docs
  • VS Code hujjati: "Source Control — Merge conflicts" — code.visualstudio.com/docs
  • npm hujjati: "package-lock.json — Resolving lockfile conflicts" — docs.npmjs.com
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Git conflict: merge conflictlarni yechish amaliyoti — IlmHamroh