4.5 Merge conflict feloldása

← 4. Git és verziókezelés a gyakorlatban

4.5 Merge conflict – feloldás pánikmentesen

Áttekintő

Első merge conflict láttán szinte mindenki lefagy. A terminál pirossal kiírja: CONFLICT, a fájl teliszórva furcsa <<<<<<< jelekkel, a kollégák várják a PR-t – és te nem tudod, mit csinálj.

Ez teljesen normális. A merge conflict nem egy hiba, amit te követtél el. Nem is katasztrófa. Egyszerűen arról van szó, hogy ketten módosítottatok ugyanazon a helyen, és a Gitnek fogalma sincs, melyik verziót tartsuk meg.

Ez az alfejezet megmutatja:

  • miért keletkezik merge conflict
  • hogyan olvasd a conflict markereket
  • lépésről lépésre hogyan old fel pánik nélkül
  • mikor kell bevonni a szerzőt
  • hogyan maradj kevesebb conflicttal hosszú távon

Részletes leírás

Miért keletkezik merge conflict?

A Git nagyon okos. Legtöbbször simán össze tudja fésülni két ember munkáját – ha különböző fájlokat módosítottatok, vagy ugyanazon fájl különböző részeit.

Conflict akkor keletkezik, ha:

  • Ketten módosítottatok ugyanazon a soron (vagy közvetlen közelében)
  • Valaki törölte a fájlt, valaki más meg módosította
  • Branch merge-elésekor a Git nem tudja eldönteni, melyik változat a helyes

A Git ilyenkor nem dönt helyetted. Megjelöli az ütköző részeket, és azt mondja: „Ezt ti oldjátok fel."

A conflict markerek olvasása

Amikor conflict van, a Git így jelöli meg az érintett részeket:

<<<<<<< HEAD
return user.isAdmin() ? "admin" : "user";
=======
return user.role;
>>>>>>> feature/user-roles

Amit tudnod kell:

  • <<<<<<< HEAD – a te branch-ed verziója innen kezdődik
  • ======= – elválasztó a két verzió között
  • >>>>>>> feature/user-roles – a bemergelni kívánt branch verziója idáig tart

A kettő között nincs „helyes" és „helytelen". Mindkét változtatás valaki munkája volt. A te feladatod eldönteni, mi kerüljön végül a kódba.

A feloldás lépései

1. Nyugodj meg – ez nem vészhelyzet.

Senki nem törölt el semmit. A Git megőrizte mindkét verziót. Visszaléphetsz bármikor (git merge --abort).

2. Azonosítsd az összes conflict-ot.

git status

A kimeneten minden conflict-os fájl megjelenik. Ne próbálj egyből beleugrani – először nézd meg, hány fájlban van probléma.

3. Nyisd meg az érintett fájlokat.

A legtöbb modern editor (VS Code, IntelliJ, stb.) vizuálisan jelöli a conflict-okat – mutatja mindkét verziót és kínál egyszerű feloldási gombokat (Accept Current / Accept Incoming / Accept Both).

Ha nincs ilyen eszközöd, szövegszerkesztővel is megnyithatod a fájlt és manuálisan oldod fel.

4. Minden conflict-nál döntsd el, mi maradjon.

Három eset lehetséges:

  • Az egyik verzió a helyes → Töröld a másikat és a markereket
  • Mindkettő kell → Kombináld őket (ez a leggyakoribb eset)
  • Egyik sem jó → Írd meg újra azt a részt

Fontos: a feloldás után ne maradjon marker a fájlban. Sem <<<<<<<, sem =======, sem >>>>>>>. Ha bennmarad, az szintaxishibát okoz – és nehéz észrevenni.

5. Jelöld megoldottnak.

Miután feloldottad az összes conflict-ot egy fájlban:

git add feloldott-fajl.py

6. Folytasd a merge-t.

Ha minden conflict-ot feloldottál:

git commit

A Git automatikusan generál egy merge commit üzenetet. Elfogadhatod, vagy módosíthatod.

Mikor vond be a szerzőt?

Feloldani tudod magad: ha az ütköző kód egyértelmű és érti vagy, mit csinál mindkét sor.

Kérdezz, ha:

  • Nem érted, miért módosította a másik fejlesztő azt a részt
  • A két verzió logikailag ütközik (nem csak szintaktikailag)
  • Biztosra akarsz menni, hogy nem törsz el valamit

Nem szégyen megkérdezni: „Hé, feloldottam a conflict-ot, de az a rész nem volt számomra egyértelmű – ránéznél mielőtt mergelem?"

Hogyan teszteld, hogy a feloldás helyes?

A feloldás után mindig futtasd le a teszteket, mielőtt pusholsz. Ha nincs automatizált teszt, legalább manuálisan ellenőrizd az érintett funkcionalitást.

A leggyakoribb hibaforrás: a conflict feloldása szintaktikailag helyes, de logikailag rossz. A Git nem tud erről – csak te tudod ellenőrizni.

Proaktív stratégiák: kevesebb conflict a jövőben

Szinkronizálj rendszeresen. Minél régebben nő el a branch-ed a fő ágaktól, annál több conflict lesz. Napi vagy kétnaponkénti git pull --rebase origin main sokat segít.

git pull --rebase origin main

Kis PR-ok, gyors review. Ha a PR-od egy hét után kerül mergeli, közben mások is módosíthattak ugyanazon a területen. Kis, fókuszált PR-ok → kevesebb conflict.

Kommunikáció a csapatban. Ha tudod, hogy kollégád is ugyanazon a modulon dolgozik, egyeztessetek előre. Nem kell mindig technikai megoldás – néha elég egy rövid Slack üzenet.


Életszerű példák

1. példa – klasszikus conflict két fejlesztő között

Szituáció: A main branch-en Anna módosított egy validációs függvényt. Te a feature branch-eden ugyanazt a függvényt módosítottad, más logikával. Mergeled a main-t, és:

<<<<<<< HEAD
def validate_email(email):
    return "@" in email and "." in email
=======
def validate_email(email):
    import re
    return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email))
>>>>>>> main

Mi a teendő?

  1. Nézd meg, mikor és miért módosította Anna
  2. A regex-es megközelítés robusztusabb → valószínűleg azt érdemes megtartani
  3. Ha a te változtatásod is tartalmazott valami egyedit, integráld bele
  4. Kérdezz rá, ha bizonytalan vagy: „A regex-es verzió erősebb, maradjon az, vagy volt okod az egyszerűbbre?"

Feloldás:

def validate_email(email):
    import re
    return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email))

Töröld a markereket, git add, majd folytasd.


2. példa – saját konfliktusodat okozol rebase közben

Szituáció: Rebase-eled a branch-edet, és több helyen is conflict keletkezik, mert régóta nem szinkronizáltál.

Tanulság: Rebase-nél minden commit-hoz külön-külön kell feloldani a conflict-okat. Ez idegesítő lehet, ha sok commit volt.

Mit csinálj?

  • Konfliktust oldd fel
  • git add az érintett fájlokra
  • git rebase --continue
  • Ismételd, amíg kész

Ha nagyon bonyolult lett, visszaléphetsz: git rebase --abort – és próbálod máshogy (pl. git merge main-t, ami egyben rendezi).


3. példa – conflict, amit nem értesz

Szituáció: Megnyitod a conflict-os fájlt, de fogalmad sincs, mit csinál az a kódrészlet. Mindkét verzió ismeretlen területen van.

Amit NE tegyél: Ne válaszd ki „ösztönösen" az egyiket és reméld, hogy jó lesz.

Amit tegyél:

  1. Nézd meg a git log alapján, ki írta az ütköző sorokat
  2. Írd meg nekik: „Merge conflict van az X fájlban, nem vagyok biztos a feloldásban, ránéznél?"
  3. Ha sürgős és nem elérhető, válaszd a konzervatívabb megközelítést (a meglévő, tesztelt verziót) és dokumentáld, hogy újra kell nézni

Ez nem gyengeség – ez professzionális hozzáállás.


4. példa – conflict miután „csak egy sort módosítottál"

Szituáció: Egy apró bugfixet csináltál – egy sort módosítottál. Mégis conflict van, mert a main-en ugyanaz a sor megváltozott.

Ez a leggyakoribb eset. Ilyenkor egyszerű:

  1. Értsd meg, miért módosult a main-en az a sor
  2. Integráld a bugfixedet az új kontextusba
  3. Teszteld, hogy mindkét változtatás érvényes-e

Tesztfeladatok

1. feladat – Conflict marker felismerése

Az alábbi kódrészletben merge conflict van. Azonosítsd:

  • Melyik rész a te branch-ed verziója?
  • Melyik a bemergelni kívánt branch verziója?
  • Mi a branch neve, amiből mergelsz?
<<<<<<< HEAD
const MAX_RETRY = 3;
=======
const MAX_RETRY = 5;
>>>>>>> fix/increase-retry-limit

Helyes válasz:

  • Te branch-ed: const MAX_RETRY = 3;
  • Bemergelni kívánt: const MAX_RETRY = 5;
  • Forrás branch neve: fix/increase-retry-limit

2. feladat – Lépések sorrendbe állítása

Sorold helyes sorrendbe az alábbi lépéseket merge conflict feloldásakor:

A) git commit
B) A conflict markerek eltávolítása és a helyes tartalom megőrzése
C) git status futtatása a conflict-os fájlok azonosítására
D) git add <fájlnév>
E) Az érintett fájl megnyitása szerkesztőben
F) Tesztek futtatása

Helyes sorrend: C → E → B → F → D → A


3. feladat – Igaz vagy hamis?

Döntsd el, melyik állítás igaz és melyik hamis:

a) A merge conflict mindig azt jelenti, hogy valaki hibázott.
b) A git merge --abort visszavonja a merge folyamatot és visszaállítja az eredeti állapotot.
c) Conflict feloldása után nem kell tesztelni, ha a szintaxis helyes.
d) A ======= jel felett mindig a te módosításod látható (HEAD).
e) Ha nem érted a conflict-os kódot, az egyiket kell választani ösztönösen.

Válaszok:

  • a) Hamis – conflict természetes velejárója az együttműködésnek
  • b) Igaz
  • c) Hamis – szintaktikailag helyes kód logikailag még hibás lehet
  • d) Igaz
  • e) Hamis – ilyenkor kérj segítséget a szerzőtől

4. feladat – Szimulált conflict feloldása

Az alábbi conflict-os kódrészletet kell feloldanod. A kontextus: egy API endpoint rate limiting értékét módosítottátok ketten. A te branch-eden 100-ra állítottad (forgalmi terhelés teszteléshez), a main-en a csapat 50-re változtatta (production limit). A feature branch-et mergeled main-be, és production-ba megy.

<<<<<<< HEAD
RATE_LIMIT_PER_MINUTE = 100
=======
RATE_LIMIT_PER_MINUTE = 50
>>>>>>> main

Kérdés: Melyik értéket tartanád meg és miért?

Várt válasz: A 50-et, mert ez a production limit, amit a csapat szándékosan állított be. A 100 tesztelési célra volt, production-ba nem kerülhet. Ha a tesztelési értéket meg akarod tartani, tedd environment változóba, ne hardcode-old.


5. feladat – Proaktív stratégia

Melyik az a szokás, ami a leghatékonyabban csökkenti a merge conflict-ok számát?

A) Mindig squash-olni a commit-okat push előtt
B) Rendszeresen szinkronizálni a feature branch-et a main-nel
C) Soha nem dolgozni ugyanazon a fájlon mint a kolléga
D) Conflict esetén mindig a saját verziót megtartani

Helyes válasz: B – A rendszeres szinkronizálás (git pull --rebase origin main) csökkenti az eltérések felhalmozódását, így kisebb és kezelhetőbb conflict-ok keletkeznek.


6. feladat – Mit tegyél, ha…?

Minden szituációhoz válaszd ki a helyes reakciót:

Szituáció 1: Conflict-ot oldasz fel, és a kód szintaktikailag hibás, mert bennmaradt egy <<<<<<< marker.
→ A) Commitolod és reméled, hogy senki nem veszi észre
→ B) Keresed a bennmaradt markert, törlöd és újra ellenőrzöd a fájlt

Szituáció 2: Conflict van, de nem érted, mit csinál az érintett kódrészlet.
→ A) Kiválasztod az egyiket véletlenszerűen
→ B) Megnézed a git log-ot, ki írta, és megkérdezed

Szituáció 3: Rebase közben 8 commitnál is conflict keletkezik.
→ A) git rebase --abort, majd git merge helyett
→ B) Egyesével feloldod mind a 8-at

Válaszok: 1→B, 2→B, 3→mindkettő elfogadható (a --abort és merge váltás praktikus opció, de az egyesével feloldás is működik)


7. feladat – Fogalmak párosítása

Párosítsd össze a Git parancsokat a hatásukkal:

ParancsHatás
git merge --abortA) Folytatja a rebase-t conflict feloldása után
git add <fájl>B) Visszavonja a merge folyamatot, visszaáll az eredeti állapot
git rebase --continueC) Megmutatja a conflict-os fájlokat
git statusD) Megjelöli a fájlt feloldottként

Válaszok: merge --abort → B, git add → D, rebase --continue → A, git status → C


8. feladat – Elemzés

Az alábbi conflict feloldásban mi a hiba?

Eredeti conflict:

<<<<<<< HEAD
function getUser(id) {
  return db.query("SELECT * FROM users WHERE id = " + id);
}
=======
function getUser(id) {
  return db.query("SELECT * FROM users WHERE id = ?", [id]);
}
>>>>>>> security/sql-injection-fix

Megoldás, amit egy junior adott:

function getUser(id) {
  return db.query("SELECT * FROM users WHERE id = " + id);
}

Mi a probléma?

Várt válasz: A junior a saját (HEAD) verzióját tartotta meg, ami SQL injection sérülékenységet tartalmaz. A security/sql-injection-fix branch-en lévő paraméteres lekérdezés (?, [id]) a biztonságos megoldás. Conflict feloldásakor a tartalom jelentőségét is érteni kell, nem csak szintaktikailag kell dönteni.


9. feladat – Gondolkodj hangosan

Leírtál egy új funkciót egy feature branch-en, közben a main-en is volt változás ugyanazon a fájlban. Mergeled a main-t, és conflict keletkezik egy 40 soros függvényen belül.

Írd le lépésről lépésre, mit csinálsz a conflicttól a sikeres mergig. (Nincs egyetlen helyes válasz – a gondolkodásmód számít.)

Mintaválasz:

  1. git status – megnézem, hány fájlban van conflict
  2. Megnyitom a fájlt editorban – VS Code megmutatja vizuálisan mindkét verziót
  3. Megnézem a git log-ban, mit változtatott a main-en az a rész és miért
  4. Ha értem a változtatás okát, kombináltom a két verziót (ha szükséges) vagy megtartom a helyeset
  5. Ha nem értem, megkérdezem a szerzőt mielőtt döntök
  6. Törlöm az összes marker maradványt
  7. git add a feloldott fájlra
  8. Lefuttatom a teszteket
  9. Ha minden OK, git commit
  10. Pusholom a branch-et

10. feladat – Összefoglalás

Melyik állítás írja le legjobban a merge conflict-ot?

A) Hiba, amit el kell kerülni jobb kódírással
B) A Git jelzése, hogy két változtatás ugyanazon a helyen ütközik, és emberi döntést igényel
C) Biztonsági figyelmeztetés, hogy valaki módosítani próbálta a kódodat
D) Automatikusan feloldható probléma, amit a Git általában meg tud csinálni helyetted

Helyes válasz: B – A merge conflict nem hiba, hanem jelzés: két párhuzamos változtatás ütközött, és a döntést a Git nem tudja meghozni helyetted. Ez normális része az együttműködésnek.

Scroll to Top