{"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\/de\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","title":{"rendered":"mergiraf \u2014 ein AST-orientiertes Tool f\u00fcr das dreiseitige Mergen in Git","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Die Ver\u00f6ffentlichung der Version 0.4 des Projekts mergiraf wurde bekanntgegeben. Dieses Projekt entwickelt einen Treiber f\u00fcr Git, der die M\u00f6glichkeit einer dreiseitigen Zusammenf\u00fchrung implementiert. Mergiraf unterst\u00fctzt die L\u00f6sung verschiedener Arten von Konflikten bei Zusammenf\u00fchrungen und kann f\u00fcr verschiedene Programmiersprachen und Dateiformate verwendet werden. Es ist m\u00f6glich, mergiraf als separaten Aufruf zur Behandlung der Konflikte zu nutzen, die bei der Arbeit mit dem herk\u00f6mmlichen Git auftreten, oder es kann als Ersatz f\u00fcr den Merge-Handler in Git verwendet werden, um die M\u00f6glichkeiten von Befehlen wie merge, revert, rebase und cherry-pick zu erweitern. Der Code wird unter der GPLv3-Lizenz verbreitet. In der neuen Version wurde die Unterst\u00fctzung f\u00fcr die Sprachen Python, TOML, Scala und Typescript hinzugef\u00fcgt sowie die Leistung optimiert.    <\/p>\n<p>Im Folgenden finden Sie eine detaillierte Beschreibung der Probleme, die mit mergiraf gel\u00f6st werden:    <\/p>\n<p>Software ist ein anschauliches Beispiel f\u00fcr ein \u00e4u\u00dferst komplexes System. Komplexe Systeme haben eine gemeinsame Eigenschaft \u2013 sie sind KOMPLEX \u2013 und man kann nicht erwarten, dass das gew\u00fcnschte komplexe Verhalten von selbst zuf\u00e4llig auftritt. Stattdessen entwickeln sich diese Systeme im Laufe der Zeit, Schritt f\u00fcr Schritt, und jede Mutation wird in jedem Schritt sorgf\u00e4ltig \u00fcberpr\u00fcft. Daf\u00fcr sind eine gut definierte Struktur und geeignete Werkzeuge notwendig. Die Evolution eines komplexen Systems kann als gerichteter Baum visualisiert werden, wobei die Wurzel eine leere Menge von Funktionen darstellt und jeder Knoten \u2013 mit Ausnahme der Wurzel \u2013 das Ergebnis der Anwendung einer Mutation auf seinen Elternknoten ist.     <\/p>\n<p>Im Kontext von Produkten wird jeder Knoten als \u201eVersion\u201c bezeichnet, die einen bestimmten Satz von Funktionen und Antifunktionen darstellt. Jede Ver\u00e4nderung dieses Satzes wird als Mutation betrachtet, die eine Kante in unserem gerichteten azyklischen Graphen bildet. Diese Funktionen sind von Natur aus abstrakt; sie spiegeln nicht direkt die Funktionsweisen physischer Systeme wider, sondern zeigen vielmehr, wie rationale Akteure den Nutzen dieser Systeme wahrnehmen. Um Ideen in bestehende reale Umsetzungen zu \u00fcbertragen, muss man die \u00c4rmel hochkrempeln und in *ausreichend* niedrigstufige Details eintauchen, in einer Sprache, die es erlaubt, zu erkl\u00e4ren, wie alles konkret funktioniert. In der Softwareentwicklung wird dieses Niedrigstufige meist durch Quellcode repr\u00e4sentiert.    <\/p>\n<p>Um den Quellcode schrittweise in einen Zustand zu versetzen, der das gew\u00fcnschte Verhalten zeigt, und zu dokumentieren, wie sie dorthin gelangten, stellen Programmierer ihre Arbeit in Form von Snapshots und Changesets dar. Ein Snapshot stellt einen bestimmten Zustand des Produkts mit allen niedrigstufigen Details dar, w\u00e4hrend ein Changeset den \u00dcbergang zwischen Snapshots bezeichnet. In der Regel werden Snapshots von einzelnen Changesets zu ihren Eltern erzeugt, weshalb diese Snapshots fast immer mit dem gekennzeichnet sind, was die Changesets, die sie erstellt haben, tun. Daher werden diese Begriffe oft synonym verwendet.     <\/p>\n<p>Manchmal gibt es Schnappsch\u00fcsse, die aus mehreren \u00dcberg\u00e4ngen \u2013 dem Zusammenf\u00fchren von Commits \u2013 resultieren. Mit ihnen ist es schwierig zu arbeiten, weshalb sie in der Regel vermieden werden. Moderne Open-Source-Versionierungssysteme wie Git bieten recht grundlegende M\u00f6glichkeiten zur Verwaltung von Entwicklungsabl\u00e4ufen. Sie erm\u00f6glichen Entwicklern, Schnappsch\u00fcsse in Form von gerichteten azyklischen Graphen zu organisieren, sie mit Kommentaren zu versehen und gegebenenfalls ihre Reihenfolge zu \u00e4ndern.     <\/p>\n<p>Diese Funktion erm\u00f6glicht es Entwicklern, eine semantisch bedeutungsvolle Projektgeschichte zu schreiben, die entscheidend f\u00fcr die Fehlersuche und die Beantwortung von Fragen wie \u201eWarum wurde dieses Low-Level-Detail (z. B. eine Variable) eingef\u00fchrt?\u201c, \u201eWie viel Prozent hat mein Beitrag ungef\u00e4hr zu diesem Projekt geleistet?\u201c, \u201eWann und wer hat Backdoor-Implementierungen gehackt?\u201c, \u201eWelches Low-Level-\u00c4nderung hat diese Funktion kaputtgemacht (obwohl es nicht h\u00e4tte sein d\u00fcrfen, wir haben alles \u00fcberpr\u00fcft!?)\u201c ist.    <\/p>\n<p>Versionskontrollsysteme erg\u00e4nzen dies durch das Konzept des Branchings \u2013 ein Low-Level-Begriff, der einfach einen kontinuierlichen Fragment der Low-Level-Geschichte des Projekts bedeutet, der f\u00fcr den Entwickler semantisch bedeutungsvoll ist. Branches werden normalerweise f\u00fcr spezifische Funktionsimplementierungen verwendet, manchmal werden mehrere Branches f\u00fcr verschiedene Kandidaten zur Implementierung derselben Funktion erstellt. Durch die Verwendung von Branching-Workflows (die tats\u00e4chlich Mainstream und der Standard in der Entwicklung sind, \u00fcberall und jederzeit verwendet werden), kann jeder einzelne Entwickler effektiv mit vielen konkurrierenden Branches des Projekts umgehen, von denen jede in Bezug auf den Reifegrad oder die Qualit\u00e4t unterschiedlich ist. Dies erm\u00f6glicht Entwicklern, die Ergebnisse ihrer und anderer Arbeit zu kombinieren, ohne alles jedes Mal manuell neu einzugeben.     <\/p>\n<p>In der Regel wird ein Hauptbranch erstellt, der das \u201eoffizielle\u201c Produkt repr\u00e4sentiert, von dem Seitenbranches f\u00fcr jede Funktion abgezweigt werden, die regelm\u00e4\u00dfig (idealerweise \u2013 nach jedem Commit) mit dem Hauptbranch synchronisiert werden, was es Entwicklern erm\u00f6glicht, mit der neuesten Version des Produkts zu arbeiten und gleichzeitig Funktionen zu implementieren, an denen sie gerade arbeiten, und Probleme, die aus den Aktionen anderer Entwickler resultieren, so fr\u00fch wie m\u00f6glich zu erkennen.    <\/p>\n<p>Beim Versuch, die Funktionen verschiedener Snapshots zu kombinieren (was einfach das Finden eines gemeinsamen Vorfahren und die Anwendung der Changesets, die daraus entstehen, sequentiell \u00fcber einander bedeutet, wird als Rebase bezeichnet, w\u00e4hrend Zusammenf\u00fchren - es ist fast wie Rebase, nur dass es das Commit-Grafik anders strukturiert, was dazu f\u00fchrt, dass es unpraktisch wird, damit zu arbeiten, weshalb man versucht, Zusammenf\u00fchrungen zugunsten von Rebase zu vermeiden), treten Probleme auf. Moderne Versionskontrollsysteme (VCS) verwenden interne Algorithmen zur Zusammenf\u00fchrung von \u00c4nderungen, die Dateien einfach in einzelne Zeilen zerlegen, jede Zeile als Symbol betrachten und Dateien als deren Sequenzen behandeln, und wenden dann Algorithmen zur Zusammenf\u00fchrung an, die aus der Bioinformatik stammen.     <\/p>\n<p>Leider hat diese zeilenweise Darstellung des Quellcodes nichts mit dessen Inhalt zu tun. Ihr einziges Vorz\u00fcge ist, dass sie einfach und universell ist. Die Diskrepanz f\u00fchrt zu Konflikten, was eine st\u00e4ndige Schmerzquelle f\u00fcr Entwickler darstellt. Das L\u00f6sen von Konflikten erfordert von den Entwicklern, beide Versionen des Codes sorgf\u00e4ltig zu \u00fcberpr\u00fcfen, dabei nicht nur die Abschnitte, die der zeilenweise Vergleichsalgorithmus als \u201ege\u00e4ndert\u201c oder \u201ekonfliktreich\u201c bezeichnet, sondern m\u00f6glicherweise auch das gesamte Projekt.     <\/p>\n<p>Der Entwickler muss die \u00c4nderungen verstehen, den zusammengef\u00fchrten Code manuell schreiben und alle Diskrepanzen beseitigen. Die Probleme h\u00e4ufen sich, wenn das zeilenweise Werkzeug \u00c4nderungen falsch identifiziert, was h\u00e4ufig bei gr\u00f6\u00dferen \u00c4nderungen passiert, selbst bei trivialen, wie der Formatierung des Codes. Wenn nachfolgende \u00c4nderungen nicht auf den manuell zusammengef\u00fchrten Code angewendet werden k\u00f6nnen, wird die Situation zu einem vollst\u00e4ndigen Albtraum. Trotz der erschreckenden F\u00e4lle funktioniert der zeilenweise Algorithmus in den meisten F\u00e4llen, insbesondere wenn die Entwickler aktiv versuchen, ihm keine Probleme zu bereiten. Eine M\u00f6glichkeit, solche Probleme zu minimieren, besteht darin, eine obligatorische Verarbeitung der Quellcodes mit Kanonalisierungswerkzeugen wie Black zu verlangen.    <\/p>\n<p>Nat\u00fcrlich ist die richtige L\u00f6sung f\u00fcr erschreckende F\u00e4lle (und \u00fcberhaupt, nicht nur f\u00fcr diese, ein zeilenweiser Algorithmus \u2013 dies ist eine Heuristik, die triviaal zu nicht funktionsf\u00e4higem Code f\u00fchren kann. Zum Beispiel hat ein Entwickler eine Variable umbenannt, w\u00e4hrend ein anderer in der Zwischenzeit neuen Code geschrieben hat, der diese Variable verwendet. Es wird keinen Konflikt beim Merging\/Rebasing geben, aber das Ergebnis wird nicht funktionieren) \u2013 die Verwendung des richtigen internen Modells.     <\/p>\n<p>Obwohl in diesem Bereich seit etwa 30 Jahren Forschung betrieben wird und mehrere propriet\u00e4re kommerzielle Produkte geschaffen wurden, wurden diese Forschungen bis vor kurzem nicht in praktisch anwendbare Open-Source-Produkte \u00fcberf\u00fchrt. Der Gro\u00dfteil der FOSS-L\u00f6sungen begann zu Beginn der 2010er Jahre zu wachsen und konzentrierte sich haupts\u00e4chlich auf die Programmiersprache Java.    <\/p>\n<p>Die herausragendste freie Implementierung aus dieser Zeit, GumTree, wurde von einem Forscher mit akademischem Hintergrund erstellt, ist in Java geschrieben und hat eine eigene abstrakte interne Darstellung, die treesitter vorausgeht. Sie verf\u00fcgt \u00fcber Backends, die sowohl auf treesitter als auch auf anderen Werkzeugen basieren, um Quellcode in abstrakte Darstellungen zu parsen. Dieses System kann nur generieren (in Form eines textuellen Ereignisprotokolls, au\u00dferdem gibt es eine API, die triviaal von jeder Programmiersprache mit Bindungen zu Java aufgerufen werden kann) und \u00c4nderungen visualisieren. Allerdings ist es f\u00fcr das Zusammenf\u00fchren von \u00c4nderungen sowie f\u00fcr die Ansicht der generierten Diff-Dateien von Haus aus nicht anwendbar (obwohl es wahrscheinlich ist, dass das Laden von Diffs \u00fcber die API umgesetzt werden kann).    <\/p>\n<p>Eine j\u00fcngere und praktischere Implementierung von difftastic ist in Rust geschrieben, basiert auf treesitter und konzentriert sich auf die Generierung von hervorgehobenen Diffs in der Konsole. Dieses System zielt ebenfalls auf die Visualisierung von Diffs ab und hat nicht das Ziel, \u00c4nderungen zusammenzuf\u00fchren oder Patches anzuwenden.    <\/p>\n<p>Zuletzt ist das Projekt mergiraf erschienen und entwickelt sich aktiv weiter. Dieses in Rust geschriebene Tool (nimmt 21 MiB ein!) basiert ebenfalls auf treesitter, das bereits zu einem Standard f\u00fcr Parser kontextfreier Grammatiken in Entwicklungstools geworden ist, \u00e4hnlich wie LLVM f\u00fcr die Optimierung von niedrigstufigen Repr\u00e4sentationen von Instruktionen. Im Gegensatz zu seinen Mitbewerbern bietet mergiraf Funktionen nicht zur Generierung von Diffs, sondern zur automatischen Aufl\u00f6sung von Merge-Konflikten. Unter der Haube verwendet mergiraf zur Patch-Generierung eine Implementierung des Algorithmen, der in GumTree verwendet wird, und f\u00fcr die Anwendung eine Implementierung des Algorithmus, der in spork verwendet wird, adaptiert f\u00fcr die Strukturen von treesitter.     <\/p>\n<p>Die Serialisierung von Patches in Dateien, die sp\u00e4ter angewendet werden k\u00f6nnen, ist leider noch nicht umgesetzt (es ist jedoch gut m\u00f6glich, dass dies durch das Parsen von Ereignisprotokollen, die von GumTree erzeugt werden, realisiert werden kann). Ein weiterer vielversprechender Ansatz zur Anwendung von Unterschieden k\u00f6nnte die Nutzung von Unterschieden \u00fcber funktionale Refactoring-Funktionen von LSP-Servern sein, was bei der Erkennung von Konflikten auf Projektebene helfen k\u00f6nnte. Die Visualisierung wird nur f\u00fcr Konflikte unterst\u00fctzt.    <\/p>\n<p>Beispiel: allgemeiner Vorl\u00e4ufer \u00abbase.py\u00bb (mit Tabulatoren einger\u00fcckt, \u00fcberfl\u00fcssige Zeile am Anfang) foo = 1 def main(): print(foo + 2 + 3) \u00aba.py\u00bb (mit Tabulatoren einger\u00fcckt, 2 \u00fcberfl\u00fcssige Zeilen am Anfang anstelle von einer, zur Debug-Ausgabe wird die icecream-Bibliothek verwendet, Klasse \u00abbaz\u00bb hinzugef\u00fcgt: from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): \u00ab\u00bb baz \u00ab\u00bb \u00ab\u00ab \u00ab\u00ab \u00ab\u00ab \u00ab\u00ab \u00ab\u00ab \u00ab\u00bb; \u00abb.py\u00bb (Variable \u00abfoo\u00bb wurde in \u00abbar\u00bb umbenannt, mit \u00abblack\u00bb verarbeitet nach den \u00c4nderungen, in Folge sind die Einr\u00fcckungen \u2013 mit Leerzeichen und \u00fcberfl\u00fcssige Zeilen entfernt): bar = 1 def main(): print(bar + 2 + 3) Der Aufruf .\\\/mergiraf merge .\\\/base.py .\\\/a.py .\\\/b.py -x a.py -y b.py -s base.py -o .\\\/res.py gibt das folgende Ergebnis zur\u00fcck from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): \u00ab\u00bb baz \u00ab\u00bb \u00ab\u00ab (zur Debug-Ausgabe wird die \u00abicecream\u00bb-Bibliothek verwendet, Variable \u00abfoo\u00bb wurde in \u00abbar\u00bb umbenannt, mit \u00abblack\u00bb verarbeitet nach den \u00c4nderungen, in Folge sind die Einr\u00fcckungen \u2013 mit Leerzeichen und \u00fcberfl\u00fcssigen Zeilen entfernt, Mischung aus Tabs und Leerzeichen f\u00fcr die Einr\u00fcckung, aber der erlaubte Zustand).    <\/p>\n<p>Hier zeigt sich bereits der Nachteil des Werkzeugs. Der Dokumentstil wird normalerweise in Dateien &#171;.editorconfig&#187; konfiguriert, und globale Stil\u00e4nderungen, wie die Umstellung von Tabs auf Leerzeichen und die Annahme des Black-Stils, wie es in &#171;b.py&#187; geschehen ist, gehen normalerweise mit \u00c4nderungen in &#171;.editorconfig&#187; einher. Daher sollte das Werkzeug zur korrekten Anwendung solcher \u00c4nderungen ein Konzept f\u00fcr einen globalen Standardstil haben und in der Lage sein, Einstellungen aus &#171;.editorconfig&#187; zu \u00fcbernehmen.<br \/>\n<br \/>Quelle: <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.1.1 - 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\/de\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\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\/de\/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 AST-orientiertes Werkzeug f\u00fcr dreidimensionales Zusammenf\u00fchren in Git | ProHoster","description":"Die Ver\u00f6ffentlichung des Projekts mergiraf 0.4, das einen Treiber f\u00fcr Git mit der Implementierung der M\u00f6glichkeit des Dreidimensionalen Zusammenf\u00fchrens entwickelt.","canonical_url":"https:\/\/prohoster.info\/de\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","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\/de\/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\/de\/wp-json\/wp\/v2\/posts\/120981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=120981"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/120981\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=120981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=120981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=120981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}