{"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\/fr\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","title":{"rendered":"mergiraf \u2014 un outil orient\u00e9 AST pour la fusion tripartite dans Git","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>La version 0.4 du projet mergiraf a \u00e9t\u00e9 publi\u00e9e, d\u00e9veloppant un pilote pour Git avec la possibilit\u00e9 de fusion tripartite. Mergiraf prend en charge la r\u00e9solution de divers types de conflits lors des fusions et peut \u00eatre utilis\u00e9 pour diff\u00e9rents langages de programmation et formats de fichiers. Il est possible d'appeler mergiraf s\u00e9par\u00e9ment pour traiter les conflits qui surviennent lors de l'utilisation de Git standard, ou de remplacer le gestionnaire de fusions de Git afin d'\u00e9tendre les fonctionnalit\u00e9s des commandes telles que merge, revert, rebase et cherry-pick. Le code est distribu\u00e9 sous licence GPLv3. La nouvelle version ajoute la prise en charge des langues Python, TOML, Scala et TypeScript, ainsi qu'une optimisation des performances.    <\/p>\n<p>Voici une description d\u00e9taill\u00e9e des probl\u00e8mes r\u00e9solus gr\u00e2ce \u00e0 mergiraf :    <\/p>\n<p>Le logiciel est un exemple frappant d'un syst\u00e8me extr\u00eamement complexe. Les syst\u00e8mes complexes partagent une caract\u00e9ristique commune : ils sont COMPLEXES et vous ne pouvez pas vous attendre \u00e0 ce qu'un comportement complexe \u00e9mergente tout seul, par hasard. Au lieu de cela, ces syst\u00e8mes \u00e9voluent avec le temps, pas \u00e0 pas, et chaque mutation est soigneusement v\u00e9rifi\u00e9e \u00e0 chaque \u00e9tape. Pour ce faire, une structure bien d\u00e9finie et des outils appropri\u00e9s sont n\u00e9cessaires. L'\u00e9volution de tout syst\u00e8me complexe peut \u00eatre visualis\u00e9e sous la forme d'un arbre dirig\u00e9, o\u00f9 la racine repr\u00e9sente un ensemble vide de fonctions, et chaque n\u0153ud \u2014 \u00e0 l'exception de la racine \u2014 est le r\u00e9sultat de l'application d'une mutation \u00e0 son parent.     <\/p>\n<p>Dans le contexte des produits, chaque n\u0153ud est appel\u00e9 \u00ab version \u00bb, repr\u00e9sentant un ensemble sp\u00e9cifique de fonctions et d'anti-fonctions. Toute modification de cet ensemble est consid\u00e9r\u00e9e comme une mutation, formant un bord dans notre graphe acyclique dirig\u00e9. Ces fonctions sont par nature abstraites ; elles ne refl\u00e8tent pas directement les mani\u00e8res dont fonctionnent les syst\u00e8mes physiques, mais plut\u00f4t montrent comment des agents intelligents per\u00e7oivent l'utilit\u00e9 de ces syst\u00e8mes. Pour traduire les id\u00e9es en r\u00e9alisations concr\u00e8tes dans le monde r\u00e9el, il est n\u00e9cessaire de retrousser ses manches et de plonger dans des d\u00e9tails *suffisamment* bas niveau, dans un langage qui permet d'exprimer et d'expliquer comment tout cela fonctionne concr\u00e8tement. Dans le d\u00e9veloppement de logiciels, ces bas niveaux sont g\u00e9n\u00e9ralement repr\u00e9sent\u00e9s par le code source.    <\/p>\n<p>Pour amener progressivement le code source dans un \u00e9tat qui manifeste le comportement attendu et documenter comment ils y sont parvenus, les programmeurs pr\u00e9sentent leur travail en termes de snapshots et de changesets. Un snapshot repr\u00e9sente un \u00e9tat sp\u00e9cifique du produit avec tous les d\u00e9tails de bas niveau, tandis qu'un changeset d\u00e9signe la transition entre les snapshots. En r\u00e8gle g\u00e9n\u00e9rale, les snapshots sont g\u00e9n\u00e9r\u00e9s par des changesets individuels \u00e0 leurs parents, de sorte que ces snapshots sont presque toujours marqu\u00e9s par les changesets qui les ont cr\u00e9\u00e9s, c'est pourquoi ces termes sont souvent utilis\u00e9s de mani\u00e8re interchangeable.     <\/p>\n<p>Il existe parfois des instantan\u00e9s, issus de plusieurs passes \u2014 des fusions de commits. Ils sont difficiles \u00e0 manipuler, c'est pourquoi ils sont g\u00e9n\u00e9ralement \u00e9vit\u00e9s. Les syst\u00e8mes modernes de contr\u00f4le de version open source, comme Git, offrent des capacit\u00e9s tr\u00e8s basiques pour g\u00e9rer les flux de travail de d\u00e9veloppement. Ils permettent aux d\u00e9veloppeurs d'organiser les instantan\u00e9s sous forme de graphes acycliques dirig\u00e9s, de les annoter avec des commentaires et de modifier leur ordre si n\u00e9cessaire.     <\/p>\n<p>Cette fonctionnalit\u00e9 permet aux d\u00e9veloppeurs d'\u00e9crire une histoire de projet s\u00e9mantiquement significative, ce qui est crucial pour le d\u00e9bogage et pour r\u00e9pondre \u00e0 des questions telles que : \u00ab Pourquoi ce d\u00e9tail de bas niveau (par exemple, une variable) a-t-il \u00e9t\u00e9 introduit ? \u00bb, \u00ab Quelle est approximativement ma contribution \u00e0 ce projet ? \u00bb, \u00ab Qui a \u00e9t\u00e9 victime d'une compromission lors de l'insertion de la backdoor et quand ? \u00bb, \u00ab Quel changement de bas niveau a cass\u00e9 cette fonction (m\u00eame si cela ne devrait pas avoir eu lieu, nous avons tout v\u00e9rifi\u00e9 !) ? \u00bb    <\/p>\n<p>Les syst\u00e8mes de contr\u00f4le de version compl\u00e8tent ce concept par l'id\u00e9e de branche - un concept de bas niveau qui signifie simplement un segment continu de l'historique de bas niveau du projet, s\u00e9mantiquement significatif pour le d\u00e9veloppeur. Les branches sont g\u00e9n\u00e9ralement utilis\u00e9es pour une r\u00e9alisation sp\u00e9cifique des fonctionnalit\u00e9s, plusieurs branches \u00e9tant parfois cr\u00e9\u00e9es pour diff\u00e9rents candidats \u00e0 la r\u00e9alisation de la m\u00eame fonctionnalit\u00e9. En utilisant des flux de travail avec bifurcation (qui sont en fait devenus la norme et le standard de d\u00e9veloppement, utilis\u00e9s partout), chaque d\u00e9veloppeur peut g\u00e9rer efficacement de nombreuses branches conflictuelles du projet, chacune ayant des degr\u00e9s de pr\u00e9paration ou de qualit\u00e9 diff\u00e9rents. Cela permet aux d\u00e9veloppeurs de combiner les r\u00e9sultats de leur travail et de celui des autres sans avoir \u00e0 tout r\u00e9\u00e9crire manuellement \u00e0 chaque fois.     <\/p>\n<p>En g\u00e9n\u00e9ral, une branche principale est cr\u00e9\u00e9e, repr\u00e9sentant le produit \u00ab officiel \u00bb, \u00e0 partir de laquelle des branches secondaires sont d\u00e9riv\u00e9es pour chaque fonctionnalit\u00e9, qui sont r\u00e9guli\u00e8rement (id\u00e9alement - apr\u00e8s chaque commit) synchronis\u00e9es avec la branche principale, permettant ainsi aux d\u00e9veloppeurs de travailler avec la version la plus r\u00e9cente du produit tout en int\u00e9grant les fonctionnalit\u00e9s qu'ils sont en train de d\u00e9velopper, d\u00e9tectant les probl\u00e8mes \u00e9manant des actions d'autres d\u00e9veloppeurs le plus t\u00f4t possible.    <\/p>\n<p>Lors de la tentative de combiner les fonctionnalit\u00e9s de diff\u00e9rents snapshots (qui consiste simplement \u00e0 trouver un anc\u00eatre commun et \u00e0 appliquer s\u00e9quentiellement les changesets qu'ils g\u00e9n\u00e8rent sur un autre, cette op\u00e9ration est appel\u00e9e rebase, alors que la fusion \u2014 c'est presque comme un rebase, mais qui structure le graphe des commits diff\u00e9remment, rendant alors leur manipulation difficile, c'est pourquoi on essaie souvent d'\u00e9viter les fusions au profit des rebases), des probl\u00e8mes surviennent. Les syst\u00e8mes de contr\u00f4le de version modernes (VCS) utilisent des algorithmes internes pour fusionner les changements, qui d\u00e9composent simplement les fichiers en lignes distinctes, consid\u00e9rant chaque ligne comme un symbole, et les fichiers comme leurs s\u00e9quences, puis appliquent des algorithmes pour les fusionner, issus de la bioinformatique.     <\/p>\n<p>Malheureusement, cette repr\u00e9sentation ligne par ligne du code source n\u2019a rien \u00e0 voir avec son contenu. Son unique avantage est qu'elle est simple et universelle. Ce d\u00e9calage entra\u00eene des conflits et constitue une source constante de tracas pour les d\u00e9veloppeurs. La r\u00e9solution des conflits exige du d\u00e9veloppeur qu'il examine attentivement les deux versions du code, non seulement les sections \u00e9tiquet\u00e9es par l'algorithme de comparaison ligne par ligne comme \u00ab modifi\u00e9es \u00bb ou \u00ab conflictuelles \u00bb, mais peut-\u00eatre tout le projet.     <\/p>\n<p>Le d\u00e9veloppeur doit comprendre les modifications, \u00e9crire manuellement le code fusionn\u00e9 et r\u00e9soudre toutes les incoh\u00e9rences. Les probl\u00e8mes s'accumulent lorsque l'outil ligne par ligne identifie incorrectement les changements, ce qui se produit souvent lors de modifications majeures, y compris des trivialit\u00e9s telles que le reformatage du code. Si les modifications ult\u00e9rieures ne peuvent pas \u00eatre appliqu\u00e9es au code fusionn\u00e9 manuellement, la situation devient un v\u00e9ritable cauchemar. Malgr\u00e9 les cas horribles, dans la plupart des cas, l'algorithme bas\u00e9 sur les lignes fonctionne, surtout si les d\u00e9veloppeurs s'efforcent activement de ne pas cr\u00e9er de probl\u00e8mes. L'une des fa\u00e7ons de minimiser ces probl\u00e8mes est d'exiger le traitement des sources par des outils de canonisation, comme black.    <\/p>\n<p>Il est \u00e9videmment essentiel de trouver la bonne solution pour des cas d\u00e9sastreux (et pas seulement pour eux, un algorithme ligne par ligne \u2014 c'est une heuristique, qui peut trivialement conduire \u00e0 un code non fonctionnel, par exemple, un d\u00e9veloppeur renomme une variable pendant qu'un autre \u00e9crit un nouveau morceau de code utilisant cette variable. Il n'y aura pas de conflit de fusion\/rebasage, mais le r\u00e9sultat deviendra non fonctionnel) \u2014 c'est l'utilisation d'un mod\u00e8le interne appropri\u00e9.     <\/p>\n<p>Bien que des recherches dans ce domaine soient men\u00e9es depuis environ 30 ans, ayant conduit \u00e0 la cr\u00e9ation de plusieurs produits commerciaux propri\u00e9taires, ces recherches n'avaient jusqu'\u00e0 r\u00e9cemment pas \u00e9t\u00e9 transform\u00e9es en produits pratiques \u00e0 code source ouvert. La majorit\u00e9 des solutions de logiciels libres ont commenc\u00e9 \u00e0 se d\u00e9velopper au d\u00e9but des ann\u00e9es 2010 et \u00e9taient principalement concentr\u00e9es sur le langage Java.    <\/p>\n<p>La r\u00e9alisation libre la plus remarquable de cette \u00e9poque, GumTree, a \u00e9t\u00e9 cr\u00e9\u00e9e par un chercheur ayant un bagage acad\u00e9mique, \u00e9crite en Java, et dispose de sa propre repr\u00e9sentation abstraite interne, ant\u00e9rieure \u00e0 treesitter. Elle poss\u00e8de des backends bas\u00e9s \u00e0 la fois sur treesitter et sur d'autres outils pour analyser le code source en repr\u00e9sentations abstraites. Ce syst\u00e8me peut seulement g\u00e9n\u00e9rer (sous forme de journal des \u00e9v\u00e9nements, avec une API facilement appelable depuis n'importe quel langage de programmation disposant de liaisons avec Java) et visualiser les changements. Cependant, pour la fusion des changements, de m\u00eame que pour la consultation des fichiers diff g\u00e9n\u00e9r\u00e9s, elle n'est pas adapt\u00e9e en standard (il est toutefois probable que le chargement des diffs puisse \u00eatre impl\u00e9ment\u00e9 via l'API).    <\/p>\n<p>Une r\u00e9alisation plus r\u00e9cente et plus pratique, difftastic, est \u00e9crite en Rust, bas\u00e9e sur treesitter, et se concentre sur la g\u00e9n\u00e9ration de diffs surlign\u00e9s dans la console. Ce syst\u00e8me est \u00e9galement orient\u00e9 vers la visualisation des diffs et n'a pas pour objectif la fusion des changements ou l'application de patches.    <\/p>\n<p>R\u00e9cemment, un projet nomm\u00e9 mergiraf a vu le jour et est en plein d\u00e9veloppement. Cet outil \u00e9crit en Rust (occupant 21 MiB !) est \u00e9galement bas\u00e9 sur treesitter, qui est devenu un standard pour les parseurs de grammaires contextuelles libres dans les outils de d\u00e9veloppement, tout comme LLVM l'est pour l'optimisation des repr\u00e9sentations d'instructions de bas niveau. Contrairement \u00e0 ses concurrents, mergiraf offre des fonctions non pas pour g\u00e9n\u00e9rer des diff, mais pour r\u00e9soudre automatiquement les conflits de fusion. En coulisses, mergiraf utilise pour g\u00e9n\u00e9rer des patches une impl\u00e9mentation de l'algorithme utilis\u00e9 dans GumTree, et pour l'application \u2014 une impl\u00e9mentation de l'algorithme utilis\u00e9 dans spork, adapt\u00e9es aux structures treesitter.     <\/p>\n<p>La s\u00e9rialisation des patches dans des fichiers pouvant \u00eatre appliqu\u00e9s ult\u00e9rieurement n'est malheureusement pas impl\u00e9ment\u00e9e (mais il est tout \u00e0 fait possible qu'elle puisse \u00eatre r\u00e9alis\u00e9e par l'analyse des journaux d'\u00e9v\u00e9nements g\u00e9n\u00e9r\u00e9s par GumTree). Une autre m\u00e9thode prometteuse pour appliquer les diff\u00e9rences pourrait \u00eatre l'application des diff\u00e9rences non pas par le biais de patches, mais via les fonctionnalit\u00e9s de refactoring des serveurs LSP, ce qui pourrait aider \u00e0 d\u00e9tecter des conflits au niveau de l'ensemble du projet. La visualisation est uniquement support\u00e9e pour les conflits.    <\/p>\n<p>Exemple de fonctionnement : un anc\u00eatre commun \u00ab base.py \u00bb (indentations avec des tabulations, ligne suppl\u00e9mentaire en d\u00e9but) foo = 1 def main(): print(foo + 2 + 3) \u00ab a.py \u00bb (indentations toujours avec des tabulations, 2 lignes suppl\u00e9mentaires en d\u00e9but au lieu d'une, pour l'impression de d\u00e9bogage, la biblioth\u00e8que icecream utilis\u00e9e, ajout de la classe \u00ab baz \u00bb : from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): \u00ab &gt;&gt;&gt;baz&gt;&gt;&gt; \u00bb \u00ab b.py \u00bb (variable \u00ab foo \u00bb renomm\u00e9e en \u00ab bar \u00bb, trait\u00e9e avec \u00ab black \u00bb apr\u00e8s modifications, en r\u00e9sultant les indentations \u2014 avec des espaces et les lignes suppl\u00e9mentaires supprim\u00e9es) : bar = 1 def main(): print(bar + 2 + 3) L'appel .\\mergiraf merge .\\base.py .\\a.py .\\b.py -x a.py -y b.py -s base.py -o .\\res.py donne le r\u00e9sultat suivant from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): \u00ab &gt;&gt;&gt;baz&gt;&gt;&gt; \u00bb (pour l'impression de d\u00e9bogage, la biblioth\u00e8que \u00ab icecream \u00bb a \u00e9t\u00e9 utilis\u00e9e, variable \u00ab foo \u00bb renomm\u00e9e en \u00ab bar \u00bb, trait\u00e9e avec \u00ab black \u00bb apr\u00e8s modifications, en r\u00e9sultant les indentations \u2014 avec des espaces et les lignes suppl\u00e9mentaires supprim\u00e9es, m\u00e9lange de tabulations et d'espaces pour l'indentation, mais avec un aspect valid\u00e9).    <\/p>\n<p>On voit ici le d\u00e9faut de l'outil. Le style du document est g\u00e9n\u00e9ralement configur\u00e9 dans des fichiers &#171;.editorconfig&#187;, et les modifications globales de style, comme le passage des tabulations aux espaces et l'adoption du style black, comme cela a \u00e9t\u00e9 fait dans &#171;b.py&#187;, sont g\u00e9n\u00e9ralement accompagn\u00e9es de changements dans &#171;.editorconfig&#187;. Par cons\u00e9quent, pour appliquer de telles modifications de mani\u00e8re plus appropri\u00e9e, l'outil doit avoir un concept de style global &#171;par d\u00e9faut&#187; et \u00eatre capable de r\u00e9cup\u00e9rer les param\u00e8tres \u00e0 partir de &#171;.editorconfig&#187;.<br \/>\n<br \/>Source : <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.2 - 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\/fr\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\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\/fr\/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 Outil orient\u00e9 AST pour la fusion \u00e0 trois voies dans Git | ProHoster","description":"La version du projet mergiraf 0.4 a \u00e9t\u00e9 publi\u00e9e, d\u00e9veloppant un pilote pour Git avec la mise en \u0153uvre de la possibilit\u00e9 de fusion \u00e0 trois voies.","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"fr_FR","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\/fr\/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\/fr\/wp-json\/wp\/v2\/posts\/120981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=120981"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/120981\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=120981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=120981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=120981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}