{"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\/pt\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","title":{"rendered":"mergiraf \u2014 uma ferramenta orientada a AST para mesclagem tripla no Git","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Foi lan\u00e7ada a vers\u00e3o 0.4 do projeto mergiraf, que desenvolve um driver para Git com a implementa\u00e7\u00e3o de mesclagens tridimensionais. O Mergiraf suporta a resolu\u00e7\u00e3o de v\u00e1rios tipos de conflitos durante a mesclagem e pode ser utilizado para diversas linguagens de programa\u00e7\u00e3o e formatos de arquivo. \u00c9 poss\u00edvel tanto chamar o mergiraf separadamente para lidar com conflitos que surgem ao trabalhar com o Git padr\u00e3o, quanto substituir o manipulador de mesclagens do Git para expandir as funcionalidades de comandos como merge, revert, rebase e cherry-pick. O c\u00f3digo \u00e9 distribu\u00eddo sob a licen\u00e7a GPLv3. A nova vers\u00e3o inclui suporte para as linguagens Python, TOML, Scala e Typescript, al\u00e9m de otimiza\u00e7\u00f5es de desempenho.    <\/p>\n<p>Abaixo est\u00e1 uma descri\u00e7\u00e3o detalhada dos problemas resolvidos com o mergiraf:    <\/p>\n<p>O software \u00e9 um exemplo marcante de um sistema extremamente complexo. Sistemas complexos t\u00eam uma caracter\u00edstica em comum \u2014 eles s\u00e3o COMPLEXOS \u2014 e voc\u00ea n\u00e3o pode esperar que o comportamento complexo desejado surja por conta pr\u00f3pria, por acaso. Em vez disso, esses sistemas evoluem ao longo do tempo, passo a passo, e cada muta\u00e7\u00e3o \u00e9 cuidadosamente verificada em cada etapa. Para alcan\u00e7ar isso, uma estrutura bem definida e ferramentas adequadas s\u00e3o necess\u00e1rias. A evolu\u00e7\u00e3o de qualquer sistema complexo pode ser visualizada como uma \u00e1rvore direcionada, onde a raiz representa um conjunto vazio de fun\u00e7\u00f5es, e cada n\u00f3 \u2014 exceto a raiz \u2014 \u00e9 o resultado da aplica\u00e7\u00e3o de uma muta\u00e7\u00e3o ao seu pai.     <\/p>\n<p>No contexto dos produtos, cada n\u00f3 \u00e9 chamado de \"vers\u00e3o\", representando um conjunto espec\u00edfico de fun\u00e7\u00f5es e antifun\u00e7\u00f5es. Qualquer altera\u00e7\u00e3o nesse conjunto \u00e9 considerada uma muta\u00e7\u00e3o, formando uma borda em nosso grafo ac\u00edclico direcionado. Essas fun\u00e7\u00f5es s\u00e3o, por natureza, abstratas; elas n\u00e3o refletem diretamente os modos de opera\u00e7\u00e3o de sistemas f\u00edsicos, mas demonstram como agentes racionais percebem a utilidade desses sistemas. Para traduzir ideias em implementa\u00e7\u00f5es que existem no mundo real, \u00e9 necess\u00e1rio arrega\u00e7ar as mangas e mergulhar em detalhes *suficientemente* de baixo n\u00edvel, na linguagem que pode expressar e explicar exatamente como tudo funciona. No desenvolvimento de software, esses n\u00edveis mais baixos geralmente s\u00e3o representados pelo c\u00f3digo-fonte.    <\/p>\n<p>Para trazer gradualmente o c\u00f3digo-fonte para um estado que reflita o comportamento desejado e documentar como isso foi alcan\u00e7ado, os programadores apresentam seu trabalho em termos de snapshots e changesets. Um snapshot representa um determinado estado do produto com todos os detalhes em n\u00edvel baixo, enquanto changeset se refere \u00e0 transi\u00e7\u00e3o entre snapshots. Normalmente, os snapshots s\u00e3o gerados por changesets \u00fanicos em rela\u00e7\u00e3o a seus pais, portanto, esses snapshots geralmente s\u00e3o rotulados pelo que os changesets que os criaram fazem, sendo esses termos frequentemente usados de forma intercambi\u00e1vel.     <\/p>\n<p>\u00c0s vezes existem instant\u00e2neas obtidas ap\u00f3s v\u00e1rias transi\u00e7\u00f5es \u2014 fus\u00f5es de commits. Elas s\u00e3o dif\u00edceis de trabalhar, por isso geralmente s\u00e3o evitadas. Sistemas modernos de controle de vers\u00e3o de c\u00f3digo aberto, como o Git, oferecem capacidades bastante b\u00e1sicas para gerenciar fluxos de trabalho de desenvolvimento. Eles permitem que os desenvolvedores organizem instant\u00e2neas na forma de grafos ac\u00edclicos direcionados, anotem-nas com coment\u00e1rios e, se necess\u00e1rio, alterem sua ordem.     <\/p>\n<p>Esta funcionalidade permite que os desenvolvedores escrevam uma hist\u00f3ria do projeto com significado sem\u00e2ntico, o que \u00e9 crucial para depura\u00e7\u00e3o e para responder perguntas como: 'Por que este detalhe de baixo n\u00edvel (por exemplo, uma vari\u00e1vel) foi introduzido?', 'Qual porcentagem do meu aporte est\u00e1 neste projeto?', 'Quem sofreu uma viola\u00e7\u00e3o de seguran\u00e7a e quando?', 'Qual mudan\u00e7a de baixo n\u00edvel quebrou esta fun\u00e7\u00e3o (embora n\u00e3o deveria, n\u00f3s verificamos tudo!?)'    <\/p>\n<p>Os sistemas de controle de vers\u00e3o complementam isso com o conceito de ramo \u2014 um conceito de baixo n\u00edvel que significa simplesmente um fragmento cont\u00ednuo da hist\u00f3ria de baixo n\u00edvel do projeto, semanticamente significativo para o desenvolvedor. Ramo costuma ser utilizado para implementa\u00e7\u00f5es espec\u00edficas de funcionalidades, e \u00e0s vezes v\u00e1rios ramos s\u00e3o criados para diferentes candidatos \u00e0 implementa\u00e7\u00e3o da mesma funcionalidade. Usando fluxos de trabalho com ramifica\u00e7\u00e3o (que s\u00e3o, de fato, mainstream e padr\u00e3o de desenvolvimento, usados em toda parte), cada desenvolvedor pode gerenciar efetivamente muitos ramos conflitantes do projeto, cada um com diferentes n\u00edveis de prontid\u00e3o ou qualidade. Isso permite que os desenvolvedores combinem os resultados de seu trabalho e de outros sem ter que reescrever tudo manualmente a cada vez.     <\/p>\n<p>Normalmente, \u00e9 criada uma ramifica\u00e7\u00e3o principal que representa o produto 'oficial', a partir da qual ramifica\u00e7\u00f5es laterais s\u00e3o criadas para cada funcionalidade, que s\u00e3o regularmente (idealmente \u2014 ap\u00f3s cada commit) sincronizadas com a ramifica\u00e7\u00e3o principal, permitindo que os desenvolvedores trabalhem com a vers\u00e3o mais atualizada do produto enquanto implementam funcionalidades que est\u00e3o atualmente desenvolvendo, detectando problemas resultantes das a\u00e7\u00f5es de outros desenvolvedores assim que poss\u00edvel.    <\/p>\n<p>Ao tentar combinar as fun\u00e7\u00f5es de diferentes snapshots (o que \u00e9 simplesmente encontrar um ancestral comum e aplicar sequentialmente os changesets que os geram em cima de outro, essa opera\u00e7\u00e3o \u00e9 chamada de rebase; a fus\u00e3o, por outro lado, \u00e9 quase como um rebase, apenas estruturando o gr\u00e1fico de commits de forma diferente, tornando-o dif\u00edcil de manipular, por isso as fus\u00f5es s\u00e3o frequentemente evitadas em favor de rebases), surgem problemas. Sistemas modernos de controle de vers\u00e3o (VCS) utilizam algoritmos internos de combina\u00e7\u00e3o de mudan\u00e7as que simplesmente quebram os arquivos em linhas individuais, tratando cada linha como um s\u00edmbolo, e os arquivos como suas sequ\u00eancias, aplicando algoritmos para sua combina\u00e7\u00e3o que t\u00eam origem na bioinform\u00e1tica.     <\/p>\n<p>Infelizmente, essa representa\u00e7\u00e3o linha a linha do c\u00f3digo-fonte n\u00e3o possui rela\u00e7\u00e3o com seu conte\u00fado. Sua \u00fanica vantagem \u00e9 ser simples e universal. A discrep\u00e2ncia leva a conflitos, sendo uma fonte constante de dor de cabe\u00e7a para os desenvolvedores. Resolver conflitos exige que o desenvolvedor examine cuidadosamente ambas as vers\u00f5es do c\u00f3digo, n\u00e3o apenas as se\u00e7\u00f5es marcadas pelo algoritmo de compara\u00e7\u00e3o linha a linha como 'alteradas' ou 'conflitantes', mas possivelmente todo o projeto.     <\/p>\n<p>O desenvolvedor deve entender as mudan\u00e7as, escrever manualmente o c\u00f3digo combinado e resolver quaisquer discrep\u00e2ncias. Os problemas aumentam quando a ferramenta de linha a linha identifica incorretamente as mudan\u00e7as, o que ocorre frequentemente em altera\u00e7\u00f5es grandes, incluindo triviais, como reformata\u00e7\u00e3o de c\u00f3digo. Se as altera\u00e7\u00f5es subsequentes n\u00e3o puderem ser aplicadas ao c\u00f3digo combinado manualmente, a situa\u00e7\u00e3o se torna um verdadeiro pesadelo. Apesar de casos assustadores, na maior parte das vezes o algoritmo de linha a linha funciona, especialmente se os desenvolvedores se esfor\u00e7am ativamente para n\u00e3o criar problemas para ele. Uma maneira de minimizar tais problemas \u00e9 a exig\u00eancia obrigat\u00f3ria de processar os fontes com ferramentas de canonicidade, como o black.    <\/p>\n<p>Certamente, a solu\u00e7\u00e3o correta para casos terr\u00edveis (e de fato, n\u00e3o apenas para eles, o algoritmo linha por linha \u2014 \u00e9 uma heur\u00edstica, pode trivialmente levar a um c\u00f3digo n\u00e3o funcional, por exemplo, um desenvolvedor renomeou uma vari\u00e1vel, enquanto outro escreveu um novo trecho de c\u00f3digo usando essa vari\u00e1vel, n\u00e3o haver\u00e1 conflito de mesclagem\/rebase, mas o resultado se tornar\u00e1 n\u00e3o funcional) \u2014 \u00e9 o uso de um modelo interno correto.     <\/p>\n<p>Apesar de as pesquisas nessa \u00e1rea terem sido realizadas h\u00e1 cerca de 30 anos e resultarem na cria\u00e7\u00e3o de v\u00e1rios produtos comerciais propriet\u00e1rios, essas pesquisas s\u00f3 recentemente se tornaram produtos pr\u00e1ticos aplic\u00e1veis com c\u00f3digo aberto. A maioria das solu\u00e7\u00f5es de software livre come\u00e7ou a se desenvolver no in\u00edcio dos anos 2010 e foi focada principalmente na linguagem Java.    <\/p>\n<p>A realiza\u00e7\u00e3o mais not\u00e1vel e livre daquele per\u00edodo, GumTree, foi criada por um pesquisador com forma\u00e7\u00e3o acad\u00eamica, escrita em Java, possui sua pr\u00f3pria representa\u00e7\u00e3o interna abstrata, anterior ao treesitter, e tem backends tanto baseados em treesitter quanto em outras ferramentas para analisar c\u00f3digo-fonte em representa\u00e7\u00f5es abstratas. Este sistema s\u00f3 \u00e9 capaz de gerar (na forma de um log de eventos em texto, tamb\u00e9m possui uma API que pode ser facilmente chamada de qualquer linguagem de programa\u00e7\u00e3o com bindings para Java) e visualizar altera\u00e7\u00f5es. No entanto, para mesclar altera\u00e7\u00f5es ou visualizar os arquivos diff gerados, ele n\u00e3o \u00e9 aplic\u00e1vel por padr\u00e3o (embora, provavelmente, o upload dos diffs possa ser realizado atrav\u00e9s da API).    <\/p>\n<p>Uma implementa\u00e7\u00e3o mais jovem e mais pr\u00e1tica do difftastic \u00e9 escrita em Rust, baseada em treesitter, e focada na gera\u00e7\u00e3o de diffs destacados no console. Este sistema tamb\u00e9m tem como objetivo a visualiza\u00e7\u00e3o de diffs e n\u00e3o visa a mesclagem de altera\u00e7\u00f5es ou a aplica\u00e7\u00e3o de patches.    <\/p>\n<p>Recentemente, surgiu e est\u00e1 se desenvolvendo ativamente o projeto mergiraf. Esta ferramenta escrita em Rust (ocupa 21 MiB!) tamb\u00e9m \u00e9 baseada no treesitter, que j\u00e1 se tornou um padr\u00e3o para parsers de gram\u00e1ticas livres de contexto em ferramentas de desenvolvimento, assim como o LLVM se tornou para otimiza\u00e7\u00f5es de representa\u00e7\u00f5es de instru\u00e7\u00f5es de baixo n\u00edvel. Ao contr\u00e1rio de seus concorrentes, o mergiraf oferece funcionalidades n\u00e3o para gerar diffs, mas para resolver automaticamente conflitos de mesclagens. Por tr\u00e1s do mergiraf, utiliza-se uma implementa\u00e7\u00e3o do algoritmo usado no GumTree para gerar patches, e uma implementa\u00e7\u00e3o do algoritmo usado no spork, adaptadas para estruturas treesitter.     <\/p>\n<p>A serializa\u00e7\u00e3o de patches em arquivos que podem ser aplicados posteriormente, infelizmente, n\u00e3o foi implementada (mas \u00e9 bem poss\u00edvel que possa ser realizada atrav\u00e9s da an\u00e1lise de logs de eventos gerados pelo GumTree). Outra maneira promissora de aplicar as diferen\u00e7as pode ser atrav\u00e9s da funcionalidade de refatora\u00e7\u00e3o dos servidores LSP, o que pode ajudar na detec\u00e7\u00e3o de conflitos em n\u00edvel de projeto. A visualiza\u00e7\u00e3o \u00e9 suportada apenas para conflitos.    <\/p>\n<p>Exemplo de funcionamento:  ancestral comum \u00abbase.py\u00bb (com indenta\u00e7\u00e3o por tabula\u00e7\u00f5es, linha a mais no in\u00edcio)     foo = 1     def main():        print(foo + 2 + 3)     \u00aba.py\u00bb (com indenta\u00e7\u00e3o ainda por tabula\u00e7\u00f5es, 2 linhas a mais no in\u00edcio em vez de uma, para impress\u00e3o de depura\u00e7\u00e3o \u00e9 utilizada a biblioteca icecream, adicionou-se a classe \u00abbaz\u00bb:     from icecream import ic     foo = 1     def main():        ic(foo + 2 + 3)          class baz:                def __init__(self):                        \u00ab\u00abbaz\u00bb\u00bb     \u00abb.py\u00bb (vari\u00e1vel \u00abfoo\u00bb renomeada para \u00abbar\u00bb, formatada com \u00abblack\u00bb ap\u00f3s as mudan\u00e7as, resultando em indenta\u00e7\u00e3o por espa\u00e7os e linhas a mais eliminadas):     bar = 1       def main():       print(bar + 2 + 3)      O chamado       ..\/mergiraf merge .\/\/base.py .\/\/a.py .\/\/b.py -x a.py -y b.py -s base.py -o .\/\/res.py      produz o seguinte resultado       from icecream import ic       bar = 1         def main():         ic(bar + 2 + 3)           class baz:             def __init__(self):                  \u00ab\u00abbaz\u00bb\u00bb      (para impress\u00e3o de depura\u00e7\u00e3o \u00e9 utilizada a biblioteca \u00abicecream\u00bb, vari\u00e1vel \u00abfoo\u00bb renomeada para \u00abbar\u00bb, formatada com \u00abblack\u00bb ap\u00f3s as mudan\u00e7as, resultando em indenta\u00e7\u00e3o por espa\u00e7os e linhas a mais eliminadas, misturando tabula\u00e7\u00f5es e espa\u00e7os para indenta\u00e7\u00e3o, mas com a apar\u00eancia corrigida).    <\/p>\n<p>Aqui est\u00e1 a desvantagem da ferramenta. O estilo do documento geralmente \u00e9 configurado nos arquivos &#171;.editorconfig&#187;, e mudan\u00e7as globais de estilo, como a troca de tabula\u00e7\u00f5es por espa\u00e7os e a ado\u00e7\u00e3o do estilo black, como foi feito em &#171;b.py&#187;, normalmente s\u00e3o acompanhadas de altera\u00e7\u00f5es no &#171;.editorconfig&#187;. Portanto, para uma aplica\u00e7\u00e3o mais precisa de tais altera\u00e7\u00f5es, a ferramenta deve ter um conceito de estilo global &#171;por padr\u00e3o&#187; e ser capaz de puxar as configura\u00e7\u00f5es do &#171;.editorconfig&#187;.<br \/>\n<br \/>Fonte: <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\/pt\/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=\"pt_PT\" \/>\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\/pt\/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 uma ferramenta orientada para AST para mesclagem tripla no Git | ProHoster","description":"Foi publicado o lan\u00e7amento do projeto mergiraf 0.4, desenvolvendo um driver para Git com a implementa\u00e7\u00e3o da funcionalidade de mesclagem tripla.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/news\/mergiraf-ast-orientirovannyj-instrument-dlya-tryohstoronnego-sliyaniya-v-git","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/120981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=120981"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/120981\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=120981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=120981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=120981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}