{"id":120981,"date":"2024-12-14T09:45:59","date_gmt":"2024-12-14T07:45:59","guid":{"rendered":"https:\/\/prohoster.info\/blog\/novosti-interneta\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git"},"modified":"2024-12-14T09:45:59","modified_gmt":"2024-12-14T07:45:59","slug":"mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","status":"publish","type":"post","link":"https:\/\/prohoster.info\/cs\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","title":{"rendered":"mergiraf \u2014 n\u00e1stroj orientovan\u00fd na AST pro trojstrann\u00e9 slu\u010dov\u00e1n\u00ed v Gitu","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Byl zve\u0159ejn\u011bn vyd\u00e1n\u00ed projektu mergiraf 0.4, kter\u00fd vyv\u00edj\u00ed ovlada\u010d pro Git s implementac\u00ed mo\u017enosti trojcestn\u00e9ho slou\u010den\u00ed. Mergiraf podporuje \u0159e\u0161en\u00ed r\u016fzn\u00fdch typ\u016f konflikt\u016f p\u0159i slou\u010den\u00ed a m\u016f\u017ee b\u00fdt pou\u017eit pro r\u016fzn\u00e9 programovac\u00ed jazyky a form\u00e1ty soubor\u016f. M\u016f\u017eete prov\u00e9st samostatn\u00e9 vol\u00e1n\u00ed mergiraf pro zpracov\u00e1n\u00ed konflikt\u016f, kter\u00e9 vznikaj\u00ed p\u0159i pr\u00e1ci se standardn\u00edm Gitem, nebo jej m\u016f\u017eete nastavit jako spr\u00e1vce slou\u010den\u00ed v Git, \u010d\u00edm\u017e roz\u0161\u00ed\u0159\u00edte mo\u017enosti p\u0159\u00edkaz\u016f, jako jsou merge, revert, rebase a cherry-pick. K\u00f3d je distribuov\u00e1n pod licenc\u00ed GPLv3. Nov\u00e1 verze p\u0159idala podporu jazyk\u016f Python, TOML, Scala a Typescript a tak\u00e9 byla optimalizov\u00e1na v\u00fdkonnost.    <\/p>\n<p>N\u00ed\u017ee je podrobn\u00fd popis probl\u00e9m\u016f, kter\u00e9 lze vy\u0159e\u0161it pomoc\u00ed mergiraf:    <\/p>\n<p>Softwarov\u00e9 syst\u00e9my jsou v\u00fdrazn\u00fdm p\u0159\u00edkladem extr\u00e9mn\u011b slo\u017eit\u00e9ho syst\u00e9mu. Slo\u017eit\u00e9 syst\u00e9my maj\u00ed jednu spole\u010dnou vlastnost \u2014 jsou SLO\u017dIT\u00c9 \u2014 a nelze o\u010dek\u00e1vat, \u017ee pot\u0159ebn\u00e9 slo\u017eit\u00e9 chov\u00e1n\u00ed vznikne samo od sebe, n\u00e1hodou. M\u00edsto toho tyto syst\u00e9my vyv\u00edjej\u00ed \u010dasem, krok za krokem, a ka\u017ed\u00e1 mutace je pe\u010dliv\u011b ov\u011b\u0159ena v ka\u017ed\u00e9 f\u00e1zi. K dosa\u017een\u00ed toho je pot\u0159eba dob\u0159e definovan\u00e1 struktura a odpov\u00eddaj\u00edc\u00ed n\u00e1stroje. Evoluci jak\u00e9hokoli slo\u017eit\u00e9ho syst\u00e9mu si lze p\u0159edstavit jako sm\u011brovan\u00fd strom, kde ko\u0159en reprezentuje pr\u00e1zdnou mno\u017einu funkc\u00ed a ka\u017ed\u00fd uzel \u2014 s v\u00fdjimkou ko\u0159ene \u2014 je v\u00fdsledkem aplikace mutace na sv\u00e9ho rodi\u010de.     <\/p>\n<p>V kontextu produkt\u016f se ka\u017ed\u00fd uzel naz\u00fdv\u00e1 \u201everze\u201c, kter\u00e1 p\u0159edstavuje ur\u010dit\u00fd soubor funkc\u00ed a anti-funkc\u00ed. Jak\u00e1koliv zm\u011bna tohoto souboru se pova\u017euje za mutaci, kter\u00e1 vytv\u00e1\u0159\u00ed hranu v na\u0161em sm\u011brovan\u00e9m acyklick\u00e9m grafu. Tyto funkce jsou svou podstatou abstraktn\u00ed; p\u0159\u00edmo neodr\u00e1\u017e\u00ed zp\u016fsoby fungov\u00e1n\u00ed fyzick\u00fdch syst\u00e9m\u016f, ale sp\u00ed\u0161e ilustruj\u00ed, jak rozumn\u00ed agenti vn\u00edmaj\u00ed u\u017eite\u010dnost t\u011bchto syst\u00e9m\u016f. Aby bylo mo\u017en\u00e9 p\u0159ev\u00e9st my\u0161lenky do existuj\u00edc\u00edch re\u00e1ln\u00fdch implementac\u00ed, je nutn\u00e9 p\u0159 Roll up sleeves and dive into *sufficiently* low-level details, in which one can express and explain how everything specifically works. V softwarov\u00e9m v\u00fdvoji jsou tyto n\u00edzko\u00farov\u0148ov\u00e9 detaily obvykle reprezentov\u00e1ny zdrojov\u00fdm k\u00f3dem.    <\/p>\n<p>Aby postupn\u011b p\u0159ivedli zdrojov\u00fd k\u00f3d do stavu, kter\u00fd vykazuje po\u017eadovan\u00e9 chov\u00e1n\u00ed, a zdokumentovali, jak se tam dostali, program\u00e1to\u0159i p\u0159edstavuj\u00ed svou pr\u00e1ci v pojmech snapshot\u016f a changeset\u016f. Snapshot p\u0159edstavuje ur\u010dit\u00e9 st\u00e1dium produktu se v\u0161emi n\u00edzko\u00farov\u0148ov\u00fdmi detaily, zat\u00edmco changeset ozna\u010duje p\u0159echod mezi snapshoty. Obvykle jsou snapshoty vytv\u00e1\u0159eny z jednotliv\u00fdch changeset\u016f v\u016f\u010di jejich rodi\u010d\u016fm, tak\u017ee tyto snapshoty t\u00e9m\u011b\u0159 v\u017edy ozna\u010duj\u00ed to, co d\u011blaj\u00ed changesety, kter\u00e9 je vytvo\u0159ily, a proto se tyto pojmy \u010dasto pou\u017e\u00edvaj\u00ed zam\u011bniteln\u011b.     <\/p>\n<p>N\u011bkdy existuj\u00ed sn\u00edmky, kter\u00e9 vznikly v d\u016fsledku n\u011bkolika p\u0159echod\u016f \u2014 slou\u010den\u00ed commit\u016f. S t\u011bmito je obt\u00ed\u017en\u00e9 pracovat, a proto se jim obvykle vyh\u00fdbaj\u00ed. Modern\u00ed syst\u00e9my pro spr\u00e1vu verz\u00ed s otev\u0159en\u00fdm zdrojov\u00fdm k\u00f3dem, jako je Git, poskytuj\u00ed velmi z\u00e1kladn\u00ed mo\u017enosti pro \u0159\u00edzen\u00ed pracovn\u00edch postup\u016f v\u00fdvoje. Umo\u017e\u0148uj\u00ed v\u00fdvoj\u00e1\u0159\u016fm organizovat sn\u00edmky ve form\u011b sm\u011brovan\u00fdch acyklick\u00fdch graf\u016f, anotovat je koment\u00e1\u0159i a v p\u0159\u00edpad\u011b pot\u0159eby m\u011bnit jejich po\u0159ad\u00ed.     <\/p>\n<p>Tato funk\u010dnost umo\u017e\u0148uje v\u00fdvoj\u00e1\u0159\u016fm ps\u00e1t semanticky v\u00fdznamn\u00fd p\u0159\u00edb\u011bh projektu, co\u017e je z\u00e1sadn\u00ed pro debugging a odpov\u011bdi na ot\u00e1zky jako \u201ePro\u010d byla tato n\u00edzko\u00farov\u0148ov\u00e1 \u010d\u00e1st zavedena (nap\u0159. prom\u011bnn\u00e1)?\u201c, \u201eJak\u00e9 procento p\u0159ibli\u017en\u011b p\u0159edstavuje m\u016fj p\u0159\u00edsp\u011bvek k tomuto projektu?\u201c, \u201eKdo hacknul implementaci backdooru a kdy?\u201c, \u201eJak\u00e1 n\u00edzko\u00farov\u0148ov\u00e1 zm\u011bna rozbila tuto funkci (i kdy\u017e to p\u0159ece nem\u011blo, v\u0161echno jsme zkontrolovali!?)\u201c    <\/p>\n<p>Syst\u00e9my spr\u00e1vy verz\u00ed dopl\u0148uj\u00ed tuto koncepci v\u011btve \u2014 n\u00edzko\u00farov\u0148ov\u00fd pojem, kter\u00fd znamen\u00e1 prost\u011b nep\u0159etr\u017eit\u00fd \u00faryvek n\u00edzko\u00farov\u0148ov\u00e9 historie projektu, semanticky v\u00fdznamn\u00fd pro v\u00fdvoj\u00e1\u0159e. V\u011btve se obvykle pou\u017e\u00edvaj\u00ed pro konkr\u00e9tn\u00ed realizaci funkc\u00ed, n\u011bkdy se vytv\u00e1\u0159\u00ed n\u011bkolik v\u011btv\u00ed pro r\u016fzn\u00e9 kandid\u00e1ty na implementaci jedn\u00e9 a t\u00e9 sam\u00e9 funkce. Pou\u017e\u00edv\u00e1n\u00edm pracovn\u00edch postup\u016f s v\u011btven\u00edm (co\u017e je skuto\u010dn\u011b mainstream a standard v\u00fdvoje, pou\u017e\u00edv\u00e1 se v\u0161ude a na ka\u017ed\u00e9m kroku) m\u016f\u017ee ka\u017ed\u00fd jednotliv\u00fd v\u00fdvoj\u00e1\u0159 efektivn\u011b \u0159\u00eddit mnoho konfliktuj\u00edc\u00edch v\u011btv\u00ed projektu, p\u0159i\u010dem\u017e ka\u017ed\u00e1 z nich se li\u0161\u00ed stupn\u011bm p\u0159ipravenosti nebo kvality. To umo\u017e\u0148uje v\u00fdvoj\u00e1\u0159\u016fm kombinovat v\u00fdsledky jejich a ciz\u00edch snah, ani\u017e by poka\u017ed\u00e9 museli v\u0161e p\u0159episovat ru\u010dn\u011b.     <\/p>\n<p>Obvykle je vytvo\u0159ena hlavn\u00ed v\u011btev, kter\u00e1 p\u0159edstavuje \u201eofici\u00e1ln\u00ed\u201c produkt, od kter\u00e9 odbo\u010duj\u00ed bo\u010dn\u00ed v\u011btve pro ka\u017edou funkci, kter\u00e9 se pravideln\u011b (ide\u00e1ln\u011b \u2014 po ka\u017ed\u00e9m commitu) synchronizuj\u00ed s hlavn\u00ed v\u011btv\u00ed, co\u017e umo\u017e\u0148uje v\u00fdvoj\u00e1\u0159\u016fm pracovat s nejnov\u011bj\u0161\u00ed verz\u00ed produktu a z\u00e1rove\u0148 implementovat funkce, kter\u00e9 pr\u00e1v\u011b vyv\u00edjej\u00ed, a odhalovat probl\u00e9my vypl\u00fdvaj\u00edc\u00ed z \u010dinnosti dal\u0161\u00edch v\u00fdvoj\u00e1\u0159\u016f co nejd\u0159\u00edve.    <\/p>\n<p>P\u0159i pokusu o kombinov\u00e1n\u00ed funkc\u00ed r\u016fzn\u00fdch snapshot\u016f (co\u017e je vlastn\u011b nalezen\u00ed spole\u010dn\u00e9ho p\u0159edka a aplikace zm\u011bnov\u00fdch sad, kter\u00e9 je generuj\u00ed, postupn\u011b na jinou, se t\u00e9to operaci \u0159\u00edk\u00e1 rebase; slou\u010den\u00ed je t\u00e9m\u011b\u0159 jako rebase, jen strukturuje graf commit\u016f jinak, co\u017e zt\u011b\u017euje manipulaci, proto se od slou\u010den\u00ed \u010dasto upou\u0161t\u00ed ve prosp\u011bch rebase) vznikaj\u00ed probl\u00e9my. Modern\u00ed syst\u00e9my spr\u00e1vy verz\u00ed (VCS) pou\u017e\u00edvaj\u00ed intern\u00ed algoritmy pro slu\u010dov\u00e1n\u00ed zm\u011bn, kter\u00e9 jednodu\u0161e rozd\u011bluj\u00ed soubory na jednotliv\u00e9 \u0159\u00e1dky, pova\u017euj\u00ed ka\u017ed\u00fd \u0159\u00e1dek za symbol a soubory za jejich sekvence, a pot\u00e9 aplikuj\u00ed algoritmy pro jejich slu\u010dov\u00e1n\u00ed, kter\u00e9 poch\u00e1zej\u00ed z bioinformatiky.     <\/p>\n<p>Bohu\u017eel, takov\u00e9 \u0159\u00e1dkov\u00e9 zobrazen\u00ed zdrojov\u00e9ho k\u00f3du nem\u00e1 nic spole\u010dn\u00e9ho s jeho obsahem. Jeho jedinou v\u00fdhodou je, \u017ee je jednoduch\u00e9 a univerz\u00e1ln\u00ed. Nesoulad vede ke konflikt\u016fm a je neust\u00e1l\u00fdm zdrojem bolest\u00ed hlavy pro v\u00fdvoj\u00e1\u0159e. \u0158e\u0161en\u00ed konflikt\u016f vy\u017eaduje, aby se v\u00fdvoj\u00e1\u0159 pe\u010dliv\u011b pod\u00edval na ob\u011b verze k\u00f3du, a to nejen na \u010d\u00e1sti, kter\u00e9 \u0159\u00e1dkov\u00fd algoritmus porovn\u00e1n\u00ed ozna\u010duje jako 'zm\u011bn\u011bn\u00e9' nebo 'konfliktn\u00ed', ale mo\u017en\u00e1 i na cel\u00fd projekt.     <\/p>\n<p>V\u00fdvoj\u00e1\u0159 mus\u00ed pochopit zm\u011bny, ru\u010dn\u011b napsat slou\u010den\u00fd k\u00f3d a odstranit jak\u00e9koli nesrovnalosti. Probl\u00e9m\u016f v\u00fdrazn\u011b p\u0159ib\u00fdv\u00e1, kdy\u017e \u0159\u00e1dkov\u00fd n\u00e1stroj nespr\u00e1vn\u011b identifikuje zm\u011bny, co\u017e se \u010dasto st\u00e1v\u00e1 p\u0159i v\u011bt\u0161\u00edch \u00faprav\u00e1ch, v\u010detn\u011b trivi\u00e1ln\u00edch, jako je p\u0159eform\u00e1tov\u00e1n\u00ed k\u00f3du. Pokud se n\u00e1sledn\u00e9 zm\u011bny nedaj\u00ed aplikovat na ru\u010dn\u011b slou\u010den\u00fd k\u00f3d, situace se prom\u011bn\u00ed v naprost\u00fd no\u010dn\u00ed m\u016fru. P\u0159esto\u017ee se vyskytuj\u00ed d\u011bsiv\u00e9 p\u0159\u00edpady, v drtiv\u00e9 v\u011bt\u0161in\u011b p\u0159\u00edpad\u016f \u0159\u00e1dkov\u00fd algoritmus funguje, zejm\u00e9na pokud se v\u00fdvoj\u00e1\u0159i aktivn\u011b sna\u017e\u00ed mu nezp\u016fsobovat probl\u00e9my. Jeden ze zp\u016fsob\u016f, jak minimalizovat podobn\u00e9 probl\u00e9my, je povinn\u00e9 zpracov\u00e1n\u00ed zdrojov\u00fdch k\u00f3d\u016f n\u00e1stroji pro kanonizaci, jako je black.    <\/p>\n<p>Samoz\u0159ejm\u011b, spr\u00e1vn\u00e9 \u0159e\u0161en\u00ed hr\u016fzn\u00fdch situac\u00ed (a nejen pro n\u011b, \u0159\u00e1dkov\u00fd algoritmus \u2014 to je heuristika, kter\u00e1 m\u016f\u017ee trivi\u00e1ln\u011b v\u00e9st k nefunk\u010dn\u00edmu k\u00f3du, nap\u0159\u00edklad pokud jeden v\u00fdvoj\u00e1\u0159 p\u0159ejmenuje prom\u011bnnou, zat\u00edmco druh\u00fd mezit\u00edm nap\u00ed\u0161e \u010d\u00e1st nov\u00e9ho k\u00f3du vyu\u017e\u00edvaj\u00edc\u00ed tuto prom\u011bnnou, nebude tu konfliktn\u00ed slu\u010dov\u00e1n\u00ed\/p\u0159ebazov\u00e1n\u00ed, ale v\u00fdsledek se stane nefunk\u010dn\u00edm) \u2014 je pou\u017eit\u00ed spr\u00e1vn\u00e9ho intern\u00edho modelu.     <\/p>\n<p>I kdy\u017e se v\u00fdzkum v t\u00e9to oblasti prov\u00e1d\u00ed ji\u017e asi 30 let a vedl k vytvo\u0159en\u00ed n\u011bkolika propriet\u00e1rn\u00edch komer\u010dn\u00edch produkt\u016f, tak a\u017e do ned\u00e1vna tento v\u00fdzkum nebyl p\u0159etvo\u0159en na praktick\u00e9 aplikovateln\u00e9 produkty s otev\u0159en\u00fdm zdrojov\u00fdm k\u00f3dem. Hlavn\u00ed mno\u017estv\u00ed open-source \u0159e\u0161en\u00ed za\u010dalo vznikat na za\u010d\u00e1tku 2010, a bylo zam\u011b\u0159eno p\u0159edev\u0161\u00edm na jazyk Java.    <\/p>\n<p>Nejv\u00fdznamn\u011bj\u0161\u00ed voln\u00e1 implementace t\u00e9 doby, GumTree, byla vytvo\u0159ena v\u00fdzkumn\u00edkem s akademick\u00fdm z\u00e1zem\u00edm. Je naps\u00e1na v Jav\u011b a m\u00e1 sv\u00e9 abstraktn\u00ed vnit\u0159n\u00ed zastoupen\u00ed, kter\u00e9 p\u0159edch\u00e1zelo treesitter. Disponuje backendy jak zalo\u017een\u00fdmi na treesitter, tak i na jin\u00fdch n\u00e1stroj\u00edch pro parsov\u00e1n\u00ed zdrojov\u00e9ho k\u00f3du do abstraktn\u00edch reprezentac\u00ed. Tento syst\u00e9m um\u00ed pouze generovat (ve form\u00e1tu textov\u00e9ho logu ud\u00e1lost\u00ed, existuje tak\u00e9 API, kter\u00e9 lze snadno vyvolat z jak\u00e9hokoli programovac\u00edho jazyka, kter\u00fd m\u00e1 vazby na Javu) a vizualizovat zm\u011bny. Pro slu\u010dov\u00e1n\u00ed zm\u011bn ani pro prohl\u00ed\u017een\u00ed generovan\u00fdch diff-soubor\u016f v\u0161ak nen\u00ed vhodn\u00fd (i kdy\u017e je pravd\u011bpodobn\u00e9, \u017ee na\u010dten\u00ed diff\u016f m\u016f\u017ee b\u00fdt realizov\u00e1no prost\u0159ednictv\u00edm API).    <\/p>\n<p>Mlad\u0161\u00ed a prakticky pou\u017eiteln\u011bj\u0161\u00ed implementace difftastic je napsan\u00e1 v Rustu, vych\u00e1z\u00ed z treesitter a zam\u011b\u0159uje se na generaci zv\u00fdrazn\u011bn\u00fdch diff\u016f v konzoli. Tento syst\u00e9m je tak\u00e9 orientov\u00e1n na vizualizaci diff\u016f a rozhodn\u011b nem\u00e1 za c\u00edl slu\u010dov\u00e1n\u00ed zm\u011bn \u010di aplikaci patch\u016f.    <\/p>\n<p>Ned\u00e1vno byl spu\u0161t\u011bn a aktivn\u011b se vyv\u00edj\u00ed projekt mergiraf. Tento n\u00e1stroj napsan\u00fd v Rustu (zab\u00edr\u00e1 21 MiB!) je tak\u00e9 zalo\u017een na treesitter, kter\u00fd se ji\u017e stal standardem pro parsery kontextov\u011b svobodn\u00fdch gramatik v n\u00e1stroj\u00edch pro v\u00fdvoj, tak jako se LLVM stalo standardem pro optimalizaci n\u00edzko\u00farov\u0148ov\u00fdch reprezentac\u00ed instrukc\u00ed. Na rozd\u00edl od konkurent\u016f poskytuje mergiraf funkce nikoliv pro generaci diff\u016f, ale pro automatick\u00e9 \u0159e\u0161en\u00ed konflikt\u016f slu\u010dov\u00e1n\u00ed. Mergiraf pod kapotou pou\u017e\u00edv\u00e1 implementaci algoritmu pou\u017eitou v GumTree pro generaci patch\u016f a implementaci algoritmu pou\u017eitou v spork zejm\u00e9na upravenou pro struktury treesitter.     <\/p>\n<p>Serilizace patch\u016f do soubor\u016f, kter\u00e9 mohou b\u00fdt pozd\u011bji aplikov\u00e1ny, bohu\u017eel nen\u00ed realizov\u00e1na (ale je pravd\u011bpodobn\u00e9, \u017ee by mohla b\u00fdt realizov\u00e1na pomoc\u00ed parsov\u00e1n\u00ed log\u016f ud\u00e1lost\u00ed generovan\u00fdch GumTree). Dal\u0161\u00edm perspektivn\u00edm zp\u016fsobem, jak aplikovat rozd\u00edly, m\u016f\u017ee b\u00fdt vyu\u017eit\u00ed rozd\u00edl\u016f nikoli prost\u0159ednictv\u00edm patch\u016f, ale prost\u0159ednictv\u00edm funkcionality refaktoringu LSP-server\u016f, co\u017e m\u016f\u017ee pomoci p\u0159i detekci konflikt\u016f na \u00farovni cel\u00e9ho projektu. Vizualizace je podporov\u00e1na pouze pro konflikty.    <\/p>\n<p>P\u0159\u00edklad pr\u00e1ce: obecn\u00fd p\u0159edek \u201ebase.py\u201c (odsazen\u00ed tabul\u00e1tory, nadbyte\u010dn\u00fd \u0159\u00e1dek na za\u010d\u00e1tku) foo = 1 def main(): print(foo + 2 + 3) \u201ea.py\u201c (odsazen\u00ed op\u011bt tabul\u00e1tory, 2 nadbyte\u010dn\u00e9 \u0159\u00e1dky na za\u010d\u00e1tku m\u00edsto jednoho, pro ladic\u00ed tisk je pou\u017eita knihovna icecream, p\u0159id\u00e1n t\u0159\u00edda \u201ebaz\u201c: from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): \u201e\u201ebaz\u201c\u201e \u201eb.py\u201c (prom\u011bnn\u00e1 \u201efoo\u201c byla p\u0159ejmenov\u00e1na na \u201ebar\u201c, zpracov\u00e1no pomoc\u00ed \u201eblack\u201c po zm\u011bn\u00e1ch, v\u00fdsledkem jsou odsazen\u00ed \u2014 mezerami a nadbyte\u010dn\u00e9 \u0159\u00e1dky byly odstran\u011bny): bar = 1 def main(): print(bar + 2 + 3) Vol\u00e1n\u00ed .\\mergiraf merge .\\base.py .\\a.py .\\b.py -x a.py -y b.py -s base.py -o .\\res.py d\u00e1v\u00e1 n\u00e1sleduj\u00edc\u00ed v\u00fdsledek from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): \u201e\u201ebaz\u201c\u201e (pro ladic\u00ed tisk je pou\u017eita knihovna \u201eicecream\u201c, prom\u011bnn\u00e1 \u201efoo\u201c byla p\u0159ejmenov\u00e1na na \u201ebar\u201c, zpracov\u00e1no pomoc\u00ed \u201eblack\u201c po zm\u011bn\u00e1ch, v\u00fdsledkem jsou odsazen\u00ed \u2014 mezerami a nadbyte\u010dn\u00e9 \u0159\u00e1dky byly odstran\u011bny, kombinace tabul\u00e1tor\u016f a mezer pro odsazen\u00ed, ale povolen\u00fd form\u00e1t).    <\/p>\n<p>Zde se ukazuje nev\u00fdhoda n\u00e1stroje. Styl dokumentu se obvykle konfiguruje v souborech &#171;.editorconfig&#187; a glob\u00e1ln\u00ed zm\u011bny stylu, jako je p\u0159echod z tabul\u00e1tor\u016f na mezery a p\u0159ijet\u00ed stylu black, jak bylo provedeno v &#171;b.py&#187;, v\u011bt\u0161inou doprov\u00e1z\u00ed zm\u011bny v &#171;.editorconfig&#187;. Proto by tento n\u00e1stroj m\u011bl m\u00edt koncept glob\u00e1ln\u00edho stylu &#171;v\u00fdchoz\u00edho&#187; pro spr\u00e1vn\u011bj\u0161\u00ed pou\u017eit\u00ed takov\u00fdchto zm\u011bn a m\u011bl by um\u011bt na\u010d\u00edtat nastaven\u00ed ze &#171;.editorconfig&#187;.<br \/>\n<br \/>Zdroj: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/www.opennet.ru\/opennews\/art.shtml?num=62402\">opennet.ru<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d \u0440\u0435\u043b\u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mergiraf 0.4, \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Git \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f. Mergiraf \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0432\u0438\u0434\u043e\u0432 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u043f\u0440\u0438 \u0441\u043b\u0438\u044f\u043d\u0438\u0438 \u0438 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u0444\u0430\u0439\u043b\u043e\u0432. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 mergiraf \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432, \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0449\u0438\u0445 \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441\u043e \u0448\u0442\u0430\u0442\u043d\u044b\u043c Git, \u0442\u0430\u043a \u0438 \u0437\u0430\u043c\u0435\u043d\u0430 \u0432 Git \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u0439 \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[702],"tags":[],"class_list":["post-120981","post","type-post","status-publish","format-standard","hentry","category-news"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d \u0440\u0435\u043b\u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mergiraf 0.4, \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Git \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/cs\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"cs_CZ\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47mergiraf \u2014 AST-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u0432 Git | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d \u0440\u0435\u043b\u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mergiraf 0.4, \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Git \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/cs\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2024-12-14T07:45:59+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2024-12-14T07:45:59+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47mergiraf \u2014 n\u00e1stroj orientovan\u00fd na AST pro trojstrann\u00e9 slou\u010den\u00ed v Gitu | ProHoster","description":"Bylo zve\u0159ejn\u011bno vyd\u00e1n\u00ed projektu mergiraf 0.4, kter\u00fd vyv\u00edj\u00ed ovlada\u010d pro Git s implementac\u00ed mo\u017enosti trojstrann\u00e9ho slou\u010den\u00ed.","canonical_url":"https:\/\/prohoster.info\/cs\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"cs_CZ","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47mergiraf \u2014 AST-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u0432 Git | ProHoster","og:description":"\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d \u0440\u0435\u043b\u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mergiraf 0.4, \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Git \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0451\u0445\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u0441\u043b\u0438\u044f\u043d\u0438\u044f.","og:url":"https:\/\/prohoster.info\/cs\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2024-12-14T07:45:59+00:00","article:modified_time":"2024-12-14T07:45:59+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"120981","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 08:54:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2026-01-23 08:54:19","updated":"2026-01-23 08:54:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts\/120981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/comments?post=120981"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts\/120981\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/media?parent=120981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/categories?post=120981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/tags?post=120981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}