{"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\/es\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","title":{"rendered":"mergiraf &#8212; herramienta orientada a AST para la fusi\u00f3n tripartita en Git","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Se ha publicado la versi\u00f3n 0.4 del proyecto mergiraf, que desarrolla un controlador para Git con la implementaci\u00f3n de la capacidad de fusi\u00f3n tripartita. Mergiraf soporta la resoluci\u00f3n de varios tipos de conflictos durante la fusi\u00f3n y puede utilizarse para diversos lenguajes de programaci\u00f3n y formatos de archivos. Se puede llamar a mergiraf de forma independiente para manejar los conflictos que surgen al trabajar con Git est\u00e1ndar, as\u00ed como reemplazar el controlador de fusiones en Git para ampliar las capacidades de comandos como merge, revert, rebase y cherry-pick. El c\u00f3digo se distribuye bajo la licencia GPLv3. La nueva versi\u00f3n a\u00f1ade soporte para los lenguajes Python, TOML, Scala y Typescript, adem\u00e1s de realizar optimizaciones de rendimiento.    <\/p>\n<p>A continuaci\u00f3n se presenta una descripci\u00f3n detallada de los problemas que se resuelven utilizando mergiraf:    <\/p>\n<p>El software es un ejemplo claro de un sistema extremadamente complejo. Los sistemas complejos tienen una caracter\u00edstica com\u00fan: son COMPLICADOS, y no puedes esperar que el comportamiento complejo deseado surja por s\u00ed solo, por casualidad. En cambio, estos sistemas evolucionan con el tiempo, paso a paso, y cada mutaci\u00f3n se verifica cuidadosamente en cada etapa. Para lograr esto, se necesita una estructura bien definida y herramientas adecuadas. La evoluci\u00f3n de cualquier sistema complejo se puede visualizar como un \u00e1rbol dirigido, donde la ra\u00edz representa un conjunto vac\u00edo de funciones, y cada nodo, excepto la ra\u00edz, es el resultado de aplicar una mutaci\u00f3n a su nodo padre.     <\/p>\n<p>En el contexto de los productos, cada nodo se llama \"versi\u00f3n\", representando un conjunto espec\u00edfico de funciones y antifunciones. Cualquier cambio en este conjunto se considera una mutaci\u00f3n, formando una arista en nuestro grafo ac\u00edclico dirigido. Estas funciones son inherentemente abstractas; no reflejan directamente c\u00f3mo funcionan los sistemas f\u00edsicos, sino que demuestran c\u00f3mo los agentes racionales perciben la utilidad de estos sistemas. Para traducir las ideas en implementaciones del mundo real, es necesario arremangarse y sumergirse en detalles *suficientemente* de bajo nivel, en un lenguaje que pueda expresar y explicar c\u00f3mo funciona todo concretamente. En el desarrollo de software, estos detalles de bajo nivel suelen estar representados por el c\u00f3digo fuente.    <\/p>\n<p>Para llevar gradualmente el c\u00f3digo fuente a un estado que muestre el comportamiento deseado y documentar c\u00f3mo se lleg\u00f3 a ese punto, los programadores presentan su trabajo en t\u00e9rminos de snapshots y changesets. Un snapshot representa un estado espec\u00edfico del producto con todos los detalles de bajo nivel, mientras que un changeset denota la transici\u00f3n entre snapshots. Normalmente, los snapshots se generan a partir de cambios individuales respecto a sus padres, por lo que estos snapshots suelen estar marcados por las acciones que realizan los changesets que los crearon, por lo que estos t\u00e9rminos a menudo se utilizan de manera intercambiable.     <\/p>\n<p>A veces, existen instant\u00e1neas resultantes de varios pasos: la fusi\u00f3n de commits. Son dif\u00edciles de manejar, por lo que generalmente se evitan. Los sistemas de control de versiones modernos de c\u00f3digo abierto, como Git, ofrecen capacidades b\u00e1sicas para gestionar flujos de trabajo de desarrollo. Permiten a los desarrolladores organizar instant\u00e1neas en forma de grafos ac\u00edclicos dirigidos, anotarlas con comentarios y, si es necesario, cambiar su orden.     <\/p>\n<p>Esta funcionalidad permite a los desarrolladores escribir una historia del proyecto que tenga un significado sem\u00e1ntico, lo cual es crucial para la depuraci\u00f3n y para responder preguntas como: '\u00bfPor qu\u00e9 se introdujo este detalle de bajo nivel (por ejemplo, una variable)?', '\u00bfQu\u00e9 porcentaje aproximadamente es mi contribuci\u00f3n a este proyecto?', '\u00bfQui\u00e9n comprometi\u00f3 las implementaciones de la puerta trasera y cu\u00e1ndo?', '\u00bfQu\u00e9 cambio de bajo nivel rompi\u00f3 esta funci\u00f3n (aunque no deber\u00eda haberlo hecho, \u00a1lo hemos verificado todo!?)'    <\/p>\n<p>Los sistemas de control de versiones complementan esto con el concepto de rama, un concepto de bajo nivel que simplemente significa un fragmento continuo de la historia de bajo nivel del proyecto, sem\u00e1nticamente significativo para el desarrollador. Las ramas se utilizan normalmente para la implementaci\u00f3n espec\u00edfica de funciones, y a veces se crean varias ramas para diferentes candidatos de la misma funci\u00f3n. Al utilizar flujos de trabajo con ramificaci\u00f3n (que son en realidad la norma y el est\u00e1ndar de desarrollo, se usan en todas partes), cada desarrollador individual puede gestionar eficazmente muchas ramas conflictivas del proyecto, cada una con diferentes niveles de preparaci\u00f3n o calidad. Esto permite a los desarrolladores combinar los resultados de su trabajo y el de otros sin tener que copiar todo manualmente cada vez.     <\/p>\n<p>Normalmente se crea una rama principal que representa el producto 'oficial', a partir de la cual se ramifican ramas laterales para cada funci\u00f3n, que se sincronizan regularmente (en la idealidad, despu\u00e9s de cada commit) con la rama principal, permitiendo a los desarrolladores trabajar con la versi\u00f3n m\u00e1s reciente del producto y al mismo tiempo implementar caracter\u00edsticas en las que est\u00e1n trabajando, detectando problemas que surgen de las acciones de otros desarrolladores lo antes posible.    <\/p>\n<p>Al intentar combinar las funciones de diferentes snapshots (que simplemente consiste en encontrar un ancestro com\u00fan y aplicar los changesets que los generan, uno tras otro, esta operaci\u00f3n se llama rebase; en cambio, la fusi\u00f3n es casi como un rebase, solo que estructuran el gr\u00e1fico de commits de manera diferente, lo que hace que sea inc\u00f3modo de manipular, por lo que se tiende a evitar fusiones en favor de rebases), surgen problemas. Los sistemas modernos de control de versiones (VCS) utilizan algoritmos internos de combinaci\u00f3n de cambios que simplemente dividen los archivos en l\u00edneas individuales, tratan cada l\u00ednea como un s\u00edmbolo y los archivos como secuencias de estas, y luego aplican algoritmos para combinarlas, que provienen de la bioinform\u00e1tica.     <\/p>\n<p>Desafortunadamente, esta representaci\u00f3n l\u00ednea por l\u00ednea del c\u00f3digo fuente no tiene relaci\u00f3n alguna con su contenido. Su \u00fanica ventaja es que es simple y universal. Esta discrepancia lleva a conflictos, siendo una fuente constante de dolores de cabeza para los desarrolladores. Resolver conflictos requiere que el desarrollador examine detenidamente ambas versiones del c\u00f3digo, no solo las secciones marcadas como \"modificadas\" o \"conflictivas\" por el algoritmo l\u00ednea por l\u00ednea, sino posiblemente todo el proyecto.     <\/p>\n<p>El desarrollador debe entender los cambios, escribir manualmente un c\u00f3digo combinado y resolver cualquier discrepancia. Los problemas aumentan cuando la herramienta l\u00ednea por l\u00ednea identifica incorrectamente los cambios, lo que sucede a menudo en cambios significativos, incluidas trivialidades, como el reformatado del c\u00f3digo. Si los cambios posteriores no pueden aplicarse al c\u00f3digo combinado manualmente, la situaci\u00f3n se convierte en una pesadilla total. A pesar de los casos terror\u00edficos, en la mayor\u00eda de los casos, el algoritmo l\u00ednea por l\u00ednea funciona, especialmente si los desarrolladores se esfuerzan activamente por no causarle problemas. Una forma de minimizar estos problemas es el requisito obligatorio de procesar los fuentes con herramientas de canonicalizaci\u00f3n, como black.    <\/p>\n<p>Por supuesto, la soluci\u00f3n adecuada para casos aterradores (y en general, no solo para ellos, un algoritmo l\u00ednea por l\u00ednea \u2014 es una heur\u00edstica, puede conducir a c\u00f3digo no funcional de manera trivial, por ejemplo, un desarrollador cambi\u00f3 el nombre de una variable y otro, al mismo tiempo, escribi\u00f3 un nuevo c\u00f3digo que usa esa variable; no habr\u00e1 conflicto de fusi\u00f3n\/rebase, pero el resultado ser\u00e1 no funcional) \u2014 es utilizar un modelo interno correcto.     <\/p>\n<p>A pesar de que la investigaci\u00f3n en este campo ha estado en curso durante aproximadamente 30 a\u00f1os, y ha dado lugar a la creaci\u00f3n de varios productos comerciales propietarios, hasta hace poco, estos estudios no se hab\u00edan traducido en productos pr\u00e1cticos aplicables de c\u00f3digo abierto. La mayor\u00eda de las soluciones de software libre comenzaron a desarrollarse a principios de la d\u00e9cada de 2010, y se centraron principalmente en el lenguaje Java.    <\/p>\n<p>La implementaci\u00f3n m\u00e1s destacada de esa \u00e9poca, GumTree, fue creada por un investigador con formaci\u00f3n acad\u00e9mica, est\u00e1 escrita en Java, tiene su propia representaci\u00f3n interna abstracta, anterior a treesitter, y cuenta con backend tanto basados en treesitter como en otras herramientas para analizar c\u00f3digo fuente en representaciones abstractas. Este sistema solo puede generar (en forma de un registro de eventos en texto, tambi\u00e9n hay una API que se puede invocar f\u00e1cilmente desde cualquier lenguaje de programaci\u00f3n que tenga bindings para Java) y visualizar cambios. Sin embargo, para fusionar cambios, as\u00ed como para ver los archivos diff generados, no es apto de forma predeterminada (aunque es probable que la carga de los diffs pueda implementarse a trav\u00e9s de la API).    <\/p>\n<p>Una implementaci\u00f3n m\u00e1s joven y pr\u00e1ctica de difftastic est\u00e1 escrita en Rust, se basa en treesitter y se centra en la generaci\u00f3n de diffs resaltados en la consola. Este sistema tambi\u00e9n est\u00e1 orientado a la visualizaci\u00f3n de diffs y en absoluto tiene como objetivo la fusi\u00f3n de cambios o la aplicaci\u00f3n de parches.    <\/p>\n<p>Recientemente apareci\u00f3 y se est\u00e1 desarrollando activamente el proyecto mergiraf. Esta herramienta escrita en Rust (ocupa 21 MiB) tambi\u00e9n se basa en treesitter, que ya se ha convertido en un est\u00e1ndar para analizadores de gram\u00e1ticas libres de contexto en herramientas de desarrollo, al igual que LLVM lo es para la optimizaci\u00f3n de representaciones de instrucciones de bajo nivel. A diferencia de sus competidores, mergiraf ofrece funciones no para generar diffs, sino para la resoluci\u00f3n autom\u00e1tica de conflictos de fusi\u00f3n. En el fondo, mergiraf utiliza una implementaci\u00f3n del algoritmo utilizado en GumTree para la generaci\u00f3n de parches y una implementaci\u00f3n del algoritmo utilizado en spork para la aplicaci\u00f3n, adaptadas a las estructuras de treesitter.     <\/p>\n<p>Lamentablemente, la serializaci\u00f3n de parches en archivos que pueden aplicarse posteriormente no est\u00e1 implementada (aunque es bastante probable que se pueda lograr mediante el an\u00e1lisis de registros de eventos generados por GumTree). Otro m\u00e9todo prometedor para aplicar las diferencias puede ser hacerlo no mediante parches, sino a trav\u00e9s de la funcionalidad de refactorizaci\u00f3n de los servidores LSP, lo que podr\u00eda ayudar en la detecci\u00f3n de conflictos a nivel de proyecto. La visualizaci\u00f3n se admite solo para conflictos.    <\/p>\n<p>Ejemplo de funcionamiento: el ancestro com\u00fan \u00abbase.py\u00bb (con indentaciones de tabulaciones, l\u00ednea adicional al principio) foo = 1 def main(): print(foo + 2 + 3) \u00aba.py\u00bb (con indentaciones a\u00fan de tabulaciones, 2 l\u00edneas adicionales al principio en lugar de una, para impresi\u00f3n de depuraci\u00f3n se utiliza la biblioteca icecream, se a\u00f1adi\u00f3 la clase \u00abbaz\u00bb: from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): \u00ab\u00bbbaz\u00ab\u00bb \u00abb.py\u00bb (la variable \u00abfoo\u00bb fue renombrada a \u00abbar\u00bb, formateada con \u00abblack\u00bb despu\u00e9s de los cambios, como resultado, las indentaciones son con espacios y las l\u00edneas adicionales eliminadas): bar = 1 def main(): print(bar + 2 + 3) La llamada .\/mergiraf merge .\/base.py .\/a.py .\/b.py -x a.py -y b.py -s base.py -o .\/res.py da el siguiente resultado from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): \u00ab\u00bbbaz\u00ab\u00bb (para impresi\u00f3n de depuraci\u00f3n se utiliz\u00f3 la biblioteca \u00abicecream\u00bb, la variable \u00abfoo\u00bb fue renombrada a \u00abbar\u00bb, formateada con \u00abblack\u00bb despu\u00e9s de los cambios, como resultado, las indentaciones son con espacios y las l\u00edneas adicionales eliminadas, mezcla de tabulaciones y espacios para la indentaci\u00f3n, pero con un aspecto permitido).    <\/p>\n<p>Aqu\u00ed se puede ver la desventaja de la herramienta. El estilo del documento generalmente se configura en archivos <code>.editorconfig<\/code>, y los cambios globales de estilo, como el cambio de tabs a espacios y la adopci\u00f3n del estilo Black, como se hizo en <code>b.py<\/code>, suelen ir acompa\u00f1ados de cambios en <code>.editorconfig<\/code>. Por lo tanto, para aplicar este tipo de cambios de manera m\u00e1s correcta, la herramienta debe tener un concepto de estilo global <code>por defecto<\/code> y ser capaz de extraer configuraciones de <code>.editorconfig<\/code>.<br \/>\n<br \/>Fuente: <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\/es\/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=\"es_ES\" \/>\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\/es\/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 Herramienta orientada a AST para fusi\u00f3n de tres v\u00edas en Git | ProHoster","description":"Se ha publicado la versi\u00f3n 0.4 del proyecto mergiraf, que desarrolla un controlador para Git con la implementaci\u00f3n de la funcionalidad de fusi\u00f3n de tres v\u00edas.","canonical_url":"https:\/\/prohoster.info\/es\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","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\/es\/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\/es\/wp-json\/wp\/v2\/posts\/120981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=120981"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/120981\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=120981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=120981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=120981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}