merdž konfliktTakéMerge konflikt, konflikt při mergi, conflict markerPokročilý
Definice
Merge conflict je stav ve verzovacím systému, kdy Git nedokáže bezpečně spojit dvě změny do jednoho výsledku, protože zasahují do stejné části souboru nebo do související struktury projektu. Vývojář musí konflikt ručně vyřešit, vybrat správný obsah, otestovat výsledek a dokončit merge, rebase nebo cherry-pick.
Proč Git sloučení zastaví
Merge conflict vzniká, když Git při spojování historií neumí určit jediný správný výsledek. Typicky jde o dvě větve, které změnily stejný řádek, sousední blok nebo soubor, který jedna větev upravila a druhá smazala. Automatické sloučení by v takové chvíli mohlo potichu zahodit záměr jednoho autora, proto Git raději proces přeruší.
Konflikt není chyba Gitu ani důkaz špatné práce. Konflikt znamená, že lidské rozhodnutí má větší hodnotu než mechanické pravidlo. Častěji se objevuje u dlouho žijících větví, rozsáhlých refaktorů, hromadného formátování, generovaných souborů a změn v konfiguraci.
Co Git zapíše do pracovního stromu
Git při běžném textovém konfliktu vloží do souboru značky, které oddělí obsah z aktuální větve a obsah z připojované větve. Vývojář nemá značky ponechat v kódu, ale nahradit celý blok výslednou verzí.
<<<<<<< HEAD
return calculateTotal(items, taxRate);
=======
return calculateTotal(items, discount);
>>>>>>> feature-discountsČást HEAD představuje stav větve, ve které příkaz běží. Druhá část pochází z větve nebo commitu, který se přidává. Správné řešení může být jedna z variant, kombinace obou nebo úplně nový kód. Po úpravě se soubor označí jako vyřešený příkazem git add a sloučení se dokončí commitem nebo pokračováním rebase.
Rozhodování při opravě konfliktu
Řešení merge conflictu začíná porozuměním záměru obou změn. Samotné kliknutí na „accept current“ nebo „accept incoming“ bývá riskantní, pokud vývojář neví, proč k úpravám došlo. U kódu je vhodné spustit testy, u konfigurace ověřit výsledné prostředí a u dokumentace zkontrolovat, zda text pořád odpovídá realitě.
Dobrá praxe je řešit konflikt v malém commitu, popsat rozhodnutí ve zprávě a poslat výsledek do code review. Recenzent pak nehodnotí jen syntaxi, ale i to, zda merge nezměnil chování aplikace nechtěně.
Proč konflikty bolí v týmu a CI
Merge conflict zpomaluje tým hlavně tehdy, když se objeví až těsně před vydáním. V CI/CD pipeline konflikt obvykle zabrání sestavení ještě před testy, protože repozitář nejde sestavit do jednoho konzistentního stromu. Pravidelné synchronizování větví, menší pull requesty a domluvené vlastnictví citlivých souborů snižují pravděpodobnost náročných konfliktů.
Některé konflikty Git neoznačí značkami. Logický konflikt může projít automatickým mergem, ale aplikace se rozbije, protože dvě změny spolu významově nesedí. Právě proto merge conflict není jediný okamžik, kdy je nutná kontrola výsledku.
Příklady z praxe
Timeout změněný ve dvou větvích
Dva vývojáři změnili stejný konfigurační řádek pro timeout. Git zastaví merge, protože neumí rozhodnout, jestli má služba rychle selhat, nebo čekat déle kvůli uploadu. Řešení vyžaduje domluvu nad očekávaným chováním a následné otestování integračního scénáře.
<<<<<<< HEAD const timeoutMs = 3000; ======= const timeoutMs = 10000; >>>>>>> feature-uploadRefaktor a nová funkce v jednom souboru
Vývojář merguje větev s novými slevami do větve, kde mezitím proběhl refaktor košíku. Soubor je označený jako konfliktní, dokud vývojář neodstraní značky a nevytvoří výslednou implementaci. Po `git add` může Git pokračovat v dokončení merge.
git status # both modified: src/cart.ts # po ruční úpravě souboru git add src/cart.ts git merge --continue
Časté omyly
- MýtusStačí vždycky kliknout na accept incoming a konflikt je vyřešený.
- Ve skutečnostiVolba incoming může přepsat lokální změnu, která byla stále potřebná. Bez pochopení obou větví jde spíš o náhodné rozhodnutí než o opravu konfliktu.
- MýtusKdyž Git merge conflict neukáže, sloučení je určitě bezpečné.
- Ve skutečnostiAutomatický merge zaručuje jen textově slučitelný výsledek. Logický konflikt může vzniknout i bez značek, například když jedna změna upraví API a druhá ho dál používá starým způsobem.
Časté dotazy
- Jak se merge conflict v Gitu opravuje?
- Merge conflict se opravuje úpravou konfliktních souborů do výsledné podoby, která dává smysl pro celý projekt. Vývojář musí odstranit značky konfliktu, ponechat nebo zkombinovat relevantní části a potom soubory označit příkazem git add. U merge se následně vytvoří merge commit, u rebase se obvykle pokračuje příkazem git rebase --continue. Bez testů je oprava neúplná, protože syntakticky vyřešený konflikt může stále změnit chování aplikace.
- Proč vznikne merge conflict při git pull?
- Merge conflict při pullu vzniká proto, že git pull nejdřív stáhne vzdálené změny a potom se je pokusí začlenit do lokální větve. Lokální commity nebo neupravené soubory mohou zasahovat do stejných míst jako změny ze serveru. Git proto přeruší začlenění a nechá vývojáře rozhodnout. Bezpečný postup je zkontrolovat git status, vyřešit označené soubory a teprve potom pokračovat v merge nebo rebase podle nastavení pullu.
- Dá se merge conflict vyřešit automaticky?
- Merge conflict není možné vždy úplně automatizovat, protože správný výsledek často závisí na významu změn, ne jen na textu. Nástroje umí dobře vybrat nekolizní úpravy, zobrazit rozdíly nebo navrhnout jednu stranu konfliktu. Rozhodnutí, zda se mají změny zkombinovat, přepsat nebo upravit jinak, ale patří člověku znalému domény. Automatické řešení bez kontroly je přijatelné hlavně u mechanických souborů s jasnými pravidly.
- Čím se liší merge conflict při rebase od konfliktu při merge?
- Merge conflict při rebase se řeší podobně jako při merge, ale dopad na historii je jiný. Rebase přehrává commity jeden po druhém na nový základ, takže se konflikt může objevit opakovaně v různých commitech. Po každém vyřešení se používá git add a git rebase --continue. Výhodou je čistší lineární historie, nevýhodou je větší opatrnost u větví, které už používají další lidé.
Zdroje
- Git - git-merge Documentation(otevře se v novém okně)
- Git - Basic Branching and Merging(otevře se v novém okně)
- Git - git-status Documentation(otevře se v novém okně)
- Git - git-rerere Documentation(otevře se v novém okně)