mergiraf — nástroj orientovaný na AST pro trojstranné slučování v Gitu

Byl zveřejněn vydání projektu mergiraf 0.4, který vyvíjí ovladač pro Git s implementací možnosti trojcestného sloučení. Mergiraf podporuje řešení různých typů konfliktů při sloučení a může být použit pro různé programovací jazyky a formáty souborů. Můžete provést samostatné volání mergiraf pro zpracování konfliktů, které vznikají při práci se standardním Gitem, nebo jej můžete nastavit jako správce sloučení v Git, čímž rozšíříte možnosti příkazů, jako jsou merge, revert, rebase a cherry-pick. Kód je distribuován pod licencí GPLv3. Nová verze přidala podporu jazyků Python, TOML, Scala a Typescript a také byla optimalizována výkonnost.

Níže je podrobný popis problémů, které lze vyřešit pomocí mergiraf:

Software je výrazným příkladem extrémně složitého systému. Složené systémy mají jednu společnou vlastnost — jsou SLOŽENÉ — a nemůžete očekávat, že žádoucí složité chování vznikne samo od sebe, náhodou. Místo toho se tyto systémy vyvíjejí v průběhu času, krok za krokem, a každý mutační krok je pečlivě kontrolován na každém stupni. K tomu je zapotřebí dobře definovaná struktura a odpovídající nástroje. Evoluci jakéhokoli složitého systému lze vizualizovat jako orientované strom, kde kořen představuje prázdnou množinu funkcí a každý uzel — kromě kořene — je výsledkem aplikace mutace na svého rodiče.

V kontextu produktů se každý uzel nazývá „verze“, což představuje určitou sadu funkcí a anti-funkcí. Jakákoliv změna této sady se považuje za mutaci, která tvoří hranu v našem orientovaném acyklickém grafu. Tyto funkce jsou z podstaty abstraktní; přímo neodrážejí způsoby fungování fyzických systémů, ale spíše demonstrují, jak racionální agenti vnímají užitečnost těchto systémů. Abychom převedli myšlenky do reálných realizací, je třeba si vyhrnout rukávy a ponořit se do *dostatečně* nízkoúrovňových detailů, v jazyce, který lze použít k vyjádření a vysvětlení, jak konkrétně vše funguje. V oblasti vývoje softwaru jsou tyto nízkoúrovňové detaily obvykle představovány zdrojovým kódem.

Aby postupně přivedli zdrojový kód do stavu, který vykazuje požadované chování, a zdokumentovali, jak se tam dostali, programátoři představují svou práci v pojmech snapshotů a changesetů. Snapshot představuje určité stádium produktu se všemi nízkoúrovňovými detaily, zatímco changeset označuje přechod mezi snapshoty. Obvykle jsou snapshoty vytvářeny z jednotlivých changesetů vůči jejich rodičům, takže tyto snapshoty téměř vždy označují to, co dělají changesety, které je vytvořily, a proto se tyto pojmy často používají zaměnitelně.

Někdy existují snímky získané v důsledku několika přechodů — sloučení commitů. Práce s nimi je obtížná, a proto se jim obvykle vyhýbá. Moderní systémy správy verzí s otevřeným zdrojovým kódem, jako je Git, poskytují velmi základní možnosti pro řízení pracovních postupů vývoje. Umožňují vývojářům organizovat snímky ve formě orientovaných acyklických grafů, anotovat je komentáři a v případě potřeby měnit jejich pořadí.

Tato funkcionalita umožňuje vývojářům psát sémanticky významnou historii projektu, což je rozhodující pro ladění a odpovědi na otázky typu „Proč byla tato nízkoúrovňová část (např. proměnná) zavedena?“, „Jaké procento je přibližně mého příspěvku do tohoto projektu?“, „Kdo byl napaden zavedením backdooru a kdy?“, „Jaká nízkoúrovňová změna rozbila tuto funkci (i když by neměla, vše jsme zkontrolovali!?)“

Systémy správy verzí doplňují tuto koncepci větvení — nízkoúrovňový pojem, který jednoduše znamená kontinuální fragment nízkoúrovňové historie projektu, který je pro vývojáře semanticky významný. Větve se obvykle používají pro konkrétní implementaci funkcí a někdy se vytváří několik větví pro různé kandidáty na implementaci jedné a téže funkce. Použitím pracovních postupů s větvením (které jsou ve skutečnosti mainstreamem a standardem vývoje, používaným všude a zcela všem) může každý jednotlivý vývojář efektivně spravovat mnohé konfliktní větve projektu, z nichž každá se liší mírou připravenosti nebo kvality. To umožňuje vývojářům kombinovat výsledky jejich a cizí práce, aniž by museli manuálně přepisovat všechno každý krátil.

Obvykle se vytváří hlavní větev, představující "oficiální" produkt, od které se větví boční větve pro každou funkci, které se pravidelně (ideálně — po každém commitu) synchronizují s hlavní větví, což umožňuje vývojářům pracovat s nejnovější verzí produktu a zároveň zavádět funkce, které právě vyvíjejí, detekující problémy vyplývající z akcí jiných vývojářů co nejdříve.

Při pokusu o kombinaci funkcí různých snapshotů (což je vlastně nalezení společného předka a aplikace changesetů, které je vytvářejí, sekvenčně na další, je tato operace nazývána rebase, sloučení je pak téměř jako rebase, pouze strukturuje graf commitů jinak, což způsobuje, že se s nimi špatně manipuluje, proto se sloučení snaží vyhýbat ve prospěch rebase) vznikají problémy. Moderní systémy správy verzí (VCS) používají interní algoritmy pro slučování změn, které jednoduše rozbijí soubory na jednotlivé řádky, považují každý řádek za symbol a soubory za jejich sekvence, a poté aplikují algoritmy pro jejich sloučení, které mají kořeny v bioinformatice.

Bohužel, takto po řádcích zpracované zdrojové kódy nemají nic společného s jejich obsahem. Jejich jedinou výhodou je, že jsou jednoduché a univerzální. Nesoulad vede ke konfliktům, což je stálým zdrojem bolestí pro vývojáře. Řešení konfliktů vyžaduje, aby vývojář pečlivě prozkoumal obě verze kódu, a to nejen úseky, které jsou označeny řádkovým porovnávacím algoritmem jako „změněné“ nebo „konfliktní“, ale možná i celý projekt.

Vývojář musí porozumět změnám, ručně napsat sloučený kód a odstranit veškeré nesoulady. Problémů přibývá, když nástroj po řádcích nesprávně identifikuje změny, což se často stává při rozsáhlých úpravách, včetně triviálních, jako je přeformátování kódu. Pokud nelze pozdější změny aplikovat na ručně sloučený kód, situace se promění v úplnou noční můru. I přes děsivé situace většinou řádkový algoritmus funguje, zejména pokud se vývojáři aktivně snaží nevytvářet mu problémy. Jedním ze způsobů minimalizace podobných problémů je povinné zpracování zdrojových kódů nástroji kanonikalizace, jako je black.

Správným řešením těchto hrůzných situací (a nejen pro ně, řádkový algoritmus je heuristika, a může triviálně vést k nefunkčnímu kódu, například jeden vývojář přejmenoval proměnnou a druhý zároveň napsal část nového kódu, který použil tu proměnnou, konflikty sloučení/prebázování tu nebude, ale výsledek bude nefunkční) je použití správného vnitřního modelu.

I když se výzkum v této oblasti provádí již asi 30 let a vedl k vytvoření několika proprietárních komerčních produktů, tak až do nedávna tento výzkum nebyl přetvořen na praktické aplikovatelné produkty s otevřeným zdrojovým kódem. Hlavní množství open-source řešení začalo vznikat na začátku 2010, a bylo zaměřeno především na jazyk Java.

Nejvýznamnější volná implementace té doby, GumTree, byla vytvořena výzkumníkem s akademickým zázemím. Je napsána v Javě a má své abstraktní vnitřní zastoupení, které předcházelo treesitter. Disponuje backendy jak založenými na treesitter, tak i na jiných nástrojích pro parsování zdrojového kódu do abstraktních reprezentací. Tento systém umí pouze generovat (ve formátu textového logu událostí, existuje také API, které lze snadno vyvolat z jakéhokoli programovacího jazyka, který má vazby na Javu) a vizualizovat změny. Pro slučování změn ani pro prohlížení generovaných diff-souborů však není vhodný (i když je pravděpodobné, že načtení diffů může být realizováno prostřednictvím API).

Mladší a prakticky použitelnější implementace difftastic je napsaná v Rustu, vychází z treesitter a zaměřuje se na generaci zvýrazněných diffů v konzoli. Tento systém je také orientován na vizualizaci diffů a rozhodně nemá za cíl slučování změn či aplikaci patchů.

Nedávno vznikl a aktivně se vyvíjí projekt mergiraf. Tento nástroj napsaný v Rustu (má velikost 21 MiB!) také vychází z treesitter, který se stal standardem pro parsery kontekstově svobodných gramatik v nástrojích pro vývoj, podobně jako se LLVM stalo standardem pro optimalizaci nízkoúrovňových reprezentací instrukcí. Na rozdíl od konkurentů mergiraf poskytuje funkce ne pro generaci diffů, ale pro automatické řešení konfliktů při slučování. Pod kapotou mergiraf používá pro generaci patchů implementaci algoritmu použitou v GumTree a pro aplikaci — implementaci algoritmu použitou ve spork, upravenou pro struktury treesitter.

Serilizace patchů do souborů, které mohou být později aplikovány, bohužel není realizována (ale je pravděpodobné, že by mohla být realizována pomocí parsování logů událostí generovaných GumTree). Dalším perspektivním způsobem, jak aplikovat rozdíly, může být využití rozdílů nikoli prostřednictvím patchů, ale prostřednictvím funkcionality refaktoringu LSP-serverů, což může pomoci při detekci konfliktů na úrovni celého projektu. Vizualizace je podporována pouze pro konflikty.

Příklad práce: obecný předek „base.py“ (odsazení tabulátory, nadbytečný řádek na začátku) foo = 1 def main(): print(foo + 2 + 3) „a.py“ (odsazení zůstává tabulátory, 2 nadbytečné řádky na začátku místo jednoho, pro ladicí tisk byla využita knihovna icecream, přidána třída „baz“: from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): „““baz“““ „b.py“ (proměnná „foo“ byla přejmenována na „bar“, zpracováno pomocí „black“ po změnách, výsledkem jsou odsazení - mezery a nadbytečné řádky odstraněny): bar = 1 def main(): print(bar + 2 + 3) Vyvolání .\mergiraf merge .\base.py .\a.py .\b.py -x a.py -y b.py -s base.py -o .\res.py dává následující výsledek from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): „““baz“““ (pro ladicí tisk byla využita knihovna „icecream“, proměnná „foo“ byla přejmenována na „bar“, zpracováno pomocí „black“ po změnách, výsledkem jsou odsazení - mezery a nadbytečné řádky odstraněny, směs tabulátorů a mezer pro odsazení, ale povolený vzhled).

Zde je vidět nevýhoda nástroje. Styl dokumentu se obvykle konfiguruje v souborech „.editorconfig“, a globální změny stylu, jako je změna tabulátorů na mezery a přijetí stylu black-a, jak bylo provedeno v „b.py“, obvykle doprovází změny v „.editorconfig“. Proto by měl nástroj mít koncept pro globální styl „ve výchozím nastavení“ a umět načítat nastavení z „.editorconfig“.

Zdroj: opennet.ru

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster