{"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\/nl\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","title":{"rendered":"mergiraf \u2014 een AST-geori\u00ebnteerde tool voor driedimensionale samenvoeging in Git.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>De release van het mergiraf-project 0.4 is uitgebracht, dat een stuurprogramma voor Git ontwikkelt met de mogelijkheid voor driedimensionale samenvoeging. Mergiraf ondersteunt het oplossen van verschillende soorten conflicten bij samenvoegingen en kan worden gebruikt voor verschillende programmeertalen en bestandsformaten. Het is mogelijk om mergiraf afzonderlijk aan te roepen voor het verwerken van conflicten die ontstaan bij het gebruik van standaard Git, evenals om de merge-handler in Git te vervangen om de mogelijkheden van commando's zoals merge, revert, rebase en cherry-pick uit te breiden. De code wordt verspreid onder de GPLv3-licentie. In de nieuwe versie is ondersteuning toegevoegd voor de talen Python, TOML, Scala en Typescript, en is de prestatie geoptimaliseerd.    <\/p>\n<p>Hieronder volgt een gedetailleerde beschrijving van de problemen die met mergiraf worden opgelost:    <\/p>\n<p>Software is a striking example of an extremely complex system. Complex systems share a common trait \u2014 they are COMPLEX \u2014 and you cannot expect the necessary complex behavior to emerge on its own, by chance. Instead, these systems evolve over time, step by step, and each mutation is carefully checked at every stage. Achieving this requires a well-defined structure and appropriate tools. The evolution of any complex system can be visualized as a directed tree, where the root represents an empty set of functions, and each node \u2014 except for the root \u2014 is the result of applying a mutation to its parent.     <\/p>\n<p>In the context of products, each node is called a \u2018version,\u2019 representing a specific set of functions and anti-functions. Any change to this set is considered a mutation, forming an edge in our directed acyclic graph. These functions are inherently abstract; they do not directly reflect the ways physical systems operate, but rather demonstrate how rational agents perceive the utility of these systems. To translate ideas into existing real-world implementations, you need to roll up your sleeves and dive into *sufficiently* low-level details, in a language that can express and explain exactly how everything works. In software development, these low-level details are usually represented by source code.    <\/p>\n<p>Om de broncode geleidelijk in de toestand te brengen die het vereiste gedrag vertoont en te documenteren hoe ze dat hebben bereikt, presenteren programmeurs hun werk in termen van snapshots en changesets. Een snapshot vertegenwoordigt een bepaalde staat van het product met alle gedetailleerde laag-niveau informatie, terwijl changeset de overgang tussen snapshots aanduidt. Gewoonlijk worden snapshots voortgebracht door enkele changesets naar hun ouders, dus deze snapshots worden bijna altijd gemarkeerd door wat changesets hebben gedaan die ze hebben gecre\u00eberd; daarom worden deze termen vaak door elkaar gebruikt.     <\/p>\n<p>Sometimes there are snapshots created as a result of several passes \u2014 merging commits. They are difficult to work with, so they are usually avoided. Modern open-source version control systems, such as Git, provide very basic capabilities for managing software development workflows. They allow developers to organize snapshots as directed acyclic graphs, annotate them with comments, and change their order if necessary.     <\/p>\n<p>Deze functionaliteit stelt ontwikkelaars in staat om een semantisch significante projectgeschiedenis te schrijven, wat essentieel is voor het debuggen en het beantwoorden van vragen zoals: 'Waarom is dit low-level detail ge\u00efntroduceerd (bijv. een variabele)?', 'Wat is ongeveer mijn bijdrage aan dit project?', 'Wie heeft de backdoor-invoeringen gecompromitteerd en wanneer?', 'Welke low-level wijziging heeft deze functie verbroken (terwijl dat niet zo zou moeten zijn, we hebben alles gecontroleerd!?)'    <\/p>\n<p>Versiebeheersystemen vullen dit aan met het concept van een branch \u2013 een low-level begrip dat eenvoudigweg een voortdurend fragment van de low-level projectgeschiedenis betekent, semantisch significant voor de ontwikkelaar. Branches worden doorgaans gebruikt voor specifieke implementaties van functies, soms worden meerdere branches aangemaakt voor verschillende kandidaten voor de implementatie van dezelfde functie. Door gebruik te maken van branching-workflows (die feitelijk mainstream en de standaard in ontwikkeling zijn, overal en altijd worden gebruikt), kan elke afzonderlijke ontwikkelaar effectief omgaan met veel conflicterende branches van het project, die elk verschillen in gereedheid of kwaliteit. Dit stelt ontwikkelaars in staat om de resultaten van hun werk en dat van anderen te combineren zonder telkens alles handmatig opnieuw te typen.     <\/p>\n<p>Normaal gesproken wordt er een hoofdbranch gemaakt die het 'offici\u00eble' product vertegenwoordigt, waaruit zijbranches voor elke functie takken, die regelmatig (bij voorkeur \u2013 na elke commit) worden gesynchroniseerd met de hoofdbranch, zodat ontwikkelaars kunnen werken met de meest recente versie van het product en tegelijkertijd functies kunnen implementeren die ze momenteel ontwikkelen, waardoor problemen die voortkomen uit de acties van andere ontwikkelaars zo vroeg mogelijk worden gedetecteerd.    <\/p>\n<p>Bij het proberen te combineren van de functies van verschillende snapshots (wat simpelweg het vinden van een gemeenschappelijke voorouder is en het toepassen van de daaruit voortvloeiende changesets, opeenvolgend boven een andere, deze operatie wordt rebase genoemd, terwijl samenvoegen bijna hetzelfde is als rebase, alleen dan structureert het de commitgrafiek anders, waardoor het ongemakkelijk wordt om ermee te werken, daarom proberen mensen samenvoegingen te vermijden ten gunste van rebases) ontstaan er problemen. Moderne versiebeheersystemen (VCS) gebruiken interne algoritmen voor het samenvoegen van wijzigingen, die simpelweg bestanden opsplitsen in afzonderlijke regels, elke regel beschouwen als een teken en bestanden als hun reeksen, en vervolgens algoritmen toepassen voor hun samenvoeging, die hun oorsprong vindt in bio-informatica.     <\/p>\n<p>Helaas heeft deze regelmatige weergave van de broncode niets te maken met de inhoud ervan. Het enige voordeel is dat het eenvoudig en universeel is. Deze discrepantie leidt tot conflicten, wat een constante bron van hoofdpijn is voor ontwikkelaars. Het oplossen van conflicten vereist dat de ontwikkelaar beide versies van de code grondig bestudeert, niet alleen de secties die door het regelmatige vergelijkingsalgoritme zijn aangemerkt als 'gewijzigd' of 'conflictueus', maar mogelijk ook het hele project.     <\/p>\n<p>De ontwikkelaar moet de wijzigingen begrijpen, handmatig de gecombineerde code schrijven en eventuele discrepanties oplossen. Het aantal problemen neemt toe wanneer de regelmatige tool de wijzigingen verkeerd identificeert, wat vaak voorkomt bij grote wijzigingen, inclusief triviale zoals het herformatteren van code. Als latere wijzigingen niet kunnen worden toegepast op de handmatig gecombineerde code, wordt de situatie een complete nachtmerrie. Ondanks deze angstaanjagende gevallen, werkt het regelmatige algoritme in de meeste gevallen, vooral als ontwikkelaars actief proberen geen problemen te veroorzaken. Een van de manieren om dergelijke problemen te minimaliseren is door het verplichte gebruik van canonisatie-tools, zoals black, voor de verwerking van de bronnen.    <\/p>\n<p>Natuurlijk is de juiste oplossing voor vreselijke gevallen (en in het algemeen, niet alleen voor hen, een regel-voor-regel algoritme \u2014 dit is een heuristiek, het kan triviaal leiden tot niet-werkende code, bijvoorbeeld als een ontwikkelaar een variabele hernoemt terwijl een andere ondertussen een stuk nieuwe code schrijft dat die variabele gebruikt, er zal geen merge\/rebase-conflict zijn, maar het resultaat zal niet werken) \u2014 het gebruik van het juiste interne model.     <\/p>\n<p>Hoewel het onderzoek op dit gebied al bijna 30 jaar gaande is en heeft geleid tot de ontwikkeling van verschillende propri\u00ebtaire commerci\u00eble producten, zijn deze onderzoeken tot onlangs niet omgezet in praktisch toepasbare producten met open source. De meeste open-source oplossingen begonnen zich in het begin van de jaren 2010 te ontwikkelen en waren vooral gericht op de programmeertaal Java.    <\/p>\n<p>De meest opvallende vrije implementatie uit die tijd, GumTree, is ontwikkeld door een onderzoeker met een academische achtergrond, geschreven in Java, heeft zijn eigen abstracte interne representatie, voorafgaand aan treesitter, en heeft back-ends die zowel gebaseerd zijn op treesitter als op andere tools voor het parseren van broncode naar abstracte representaties. Dit systeem kan alleen genereren (in de vorm van een tekstlog van gebeurtenissen, er is ook een API die triviaal kan worden aangeroepen vanuit elke programmeertaal met bindings naar Java) en visualiseren van wijzigingen. Echter, voor het samenvoegen van wijzigingen, alsook voor het bekijken van de door het systeem gegenereerde diff-bestanden, is het uit de doos niet toepasbaar (hoewel het waarschijnlijk is dat het uploaden van diffs via de API kan worden gerealiseerd).    <\/p>\n<p>Een jongere en meer praktisch toepasbare implementatie van difftastic is geschreven in Rust, gebaseerd op treesitter, en is gericht op het genereren van gemarkeerde diffs in de console. Dit systeem is ook gericht op het visualiseren van diffs en heeft absoluut niet als doel wijzigingen samen te voegen of patches toe te passen.    <\/p>\n<p>Onlangs is het project mergiraf verschenen en is het actief in ontwikkeling. Dit hulpmiddel, geschreven in Rust (neemt 21 MiB in beslag!), is ook gebaseerd op treesitter, dat al een standaard is geworden voor parsers van contextvrije grammatica's in ontwikkelingshulpmiddelen, net zoals LLVM dat is geworden voor optimalisering van laag-niveau instructievoorstellingen. In tegenstelling tot concurrenten biedt mergiraf functies niet voor het genereren van diff's, maar voor automatische conflictoplossing tijdens merges. Onder de motorkap gebruikt mergiraf voor het genereren van patches een implementatie van het algoritme dat in GumTree wordt gebruikt, en voor de toepassing \u2014 een implementatie van het algoritme dat in spork wordt gebruikt, aangepast voor treesitter-structuren.     <\/p>\n<p>Helaas is de serialisatie van patches naar bestanden die later kunnen worden toegepast niet gerealiseerd (maar het is heel goed mogelijk dat dit kan worden gerealiseerd door het parseren van de logboeken van gebeurtenissen die door GumTree worden gegenereerd). Een andere veelbelovende manier om verschillen toe te passen, kan zijn door deze niet via patches toe te passen, maar via de refactoring-functionaliteit van LSP-servers, wat kan helpen bij het detecteren van conflicten op projectniveau. Visualisatie wordt alleen ondersteund voor conflicten.    <\/p>\n<p>Voorbeeld van werking: algemene voorouder \u2018base.py\u2019 (tabs als inspringing, extra regel aan het begin) foo = 1 def main(): print(foo + 2 + 3) \u2018a.py\u2019 (tabs blijven inspringing, 2 extra regels aan het begin in plaats van \u00e9\u00e9n, voor debug printing wordt de bibliotheek icecream gebruikt, klasse \u2018baz\u2019 is toegevoegd: from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): \u2018&gt;&gt;&gt;baz&gt;&gt;&gt;\u2019 \u2018b.py\u2019 (de variabele \u2018foo\u2019 is hernoemd naar \u2018bar\u2019, verwerkt met \u2018black\u2019 na wijzigingen, resulterend in inspringingen \u2014 ruimtes en extra regels zijn verwijderd): bar = 1 def main(): print(bar + 2 + 3) Aanroep .\\\/mergiraf merge .\\\/base.py .\\\/a.py .\\\/b.py -x a.py -y b.py -s base.py -o .\\\/res.py geeft de volgende uitkomst: from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): \u2018&gt;&gt;&gt;baz&gt;&gt;&gt;\u2019 (voor debug printing is de bibliotheek \u2018icecream\u2019 gebruikt, de variabele \u2018foo\u2019 is hernoemd naar \u2018bar\u2019, verwerkt met \u2018black\u2019 na wijzigingen, resulterend in inspringingen \u2014 ruimtes en extra regels zijn verwijderd, mengeling van tabs en ruimtes voor inspringing, maar de toegestane vorm).    <\/p>\n<p>Hier zien we een tekortkoming van de tool. De documentstijl wordt meestal geconfigureerd in &#171;.editorconfig&#187;, en wereldwijde stijlwijzigingen, zoals het vervangen van tabs door spaties en het aannemen van de black-stijl, zoals gedaan in &#171;b.py&#187;, gaan meestal gepaard met wijzigingen in &#171;.editorconfig&#187;. Daarom moet de tool voor een correctere toepassing van dergelijke wijzigingen een concept hebben voor de globale standaardstijl, en in staat zijn om instellingen uit &#171;.editorconfig&#187; te halen.<br \/>\n<br \/>Bron: <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\/nl\/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=\"nl_NL\" \/>\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\/nl\/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 een AST-geori\u00ebnteerde tool voor drieledige samenvoeging in Git | ProHoster","description":"De release van het project mergiraf 0.4 is gepubliceerd, die een driver voor Git ontwikkelt met de implementatie van drieledige samenvoeging.","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","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\/nl\/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\/nl\/wp-json\/wp\/v2\/posts\/120981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=120981"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/120981\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=120981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=120981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=120981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}