Existe uma diferença entre mesclagens no svn em comparação com git ou mercurial?

12

Pelo meu entendimento, o SVN é 'Fácil de ramificar. Difícil de mesclar '. Por que é que? Existe alguma diferença em como eles se fundem?


fonte

Respostas:

21

Por favor, veja minha resposta do Stack Overflow para uma situação muito concreta em que o Mercurial (e o Git) se funde sem problemas e o Subversion apresenta um conflito falso. A situação é uma refatoração simples feita em uma ramificação na qual você renomeia alguns arquivos.

No que diz respeito à resposta do tdammers, há uma série de mal-entendidos:

  • Subversion, Mercurial e Git, todos controlam instantâneos do projeto em todo o repositório. Chamá-los de versões , revisões ou conjuntos de alterações não faz diferença. Todos são instantâneos logicamente atômicos de um conjunto de arquivos.

  • O tamanho de suas confirmações não faz diferença quando se trata de mesclagem. Todos os três sistemas se fundem com o algoritmo de mesclagem padrão de três vias e as entradas para esse algoritmo são

    • melhor versão ancestral comum
    • versão em um ramo
    • versão em outro ramo

    Não importa como as duas versões de ramificação foram criadas. Você pode ter usado 1000 confirmações pequenas desde a versão ancestral ou 1 confirmação. Tudo o que importa é a versão final dos arquivos. (Sim, isso é surpreendente! Sim, muitos guias do DVCS entendem isso terrivelmente errado.)

Ele também levanta alguns bons pontos sobre as diferenças:

  • O Subversion possui algum "vodu", de onde você pode mesclar /trunk, digamos /branches/foo,. Mercurial e Git não usam esse modelo - os ramos são modelados diretamente na história. Portanto, a história se torna um gráfico acíclico direcionado em vez de linear. Este é um modelo muito mais simples que o usado pelo Subversion e corta vários casos de canto.

  • Você pode atrasar facilmente uma mesclagem ou até deixar que outra pessoa lide com ela. Se houver hg mergemuitos conflitos, você poderá pedir a seu colega de trabalho hg pulle ele terá exatamente o mesmo estado. Então ele pode hg mergee talvez ele seja melhor em resolver conflitos do que você.

    Isso é muito difícil no Subversion, onde você precisa atualizar antes de poder confirmar. Você não pode simplesmente ignorar as alterações no servidor e continuar se comprometendo em sua própria ramificação anônima. Em geral, o Subversion força você a brincar com uma cópia de trabalho suja quando você svn update. Isso é meio arriscado, pois você não armazenou suas alterações em nenhum lugar seguro. Git e Mercurial permitem que você confirme primeiro e depois atualize e mescle conforme necessário.

A verdadeira razão pela qual Git e Mercurial são melhores na fusão do que o Subversion é uma questão de implementação. Existem conflitos de renomeação que o Subversion simplesmente não consegue lidar, mesmo que seja claro qual é a resposta correta. Mercurial e Git lida com esses facilmente. Mas não há razão para o Subversion não lidar com isso também - estar centralizado certamente não é o motivo.

Martin Geisler
fonte
4
Ótima resposta! Eu votaria duas vezes se pudesse. :) Eu também acrescentaria que o livro SVN a que você se refere na resposta do SO admite claramente que "o recurso de rastreamento de mesclagem do Subversion tem uma implementação interna extremamente complexa ..." - isso por si só é uma boa indicação de que o recurso não é confiável
gnat
2
... e mesmo com essa implementação extremamente complexa, não podemos descobrir o ancestral comum corretamente, exceto em casos simples.
Jan Hudec
Sobre fusões atrasadas - não entendi - com o SVN, meu colega de trabalho pode atualizar para / fazer check-out do tronco e depois mesclar do meu ramo para ele.
Gill Bates
@GillBates: Estou falando de uma situação em que você não iniciou uma filial para o seu trabalho - quando está trabalhando trunkno SVN. Com um DVCS, você pode confirmar sem compartilhar, mas no SVN você svn commitafetará diretamente outras pessoas que trabalham no mesmo ramo. Mesmo que nós dois trabalhemos em uma filial no SVN, não posso confirmar meu trabalho sem ter que me fundir imediatamente com o seu trabalho. Isso torna os commits um pouco assustadores - o que é uma propriedade assustadora para um sistema de controle de versão! :-)
Martin Geisler
6

O principal problema está na maneira como esses sistemas representam uma estrutura de diretório com versão.

O conceito básico do Subversion em torno do qual todo o sistema gira é o de uma versão (ou, no svn lingo, "revisão"): uma captura instantânea de um arquivo em um determinado ponto. Desde que a história seja perfeitamente linear, tudo está bem, mas se você precisar mesclar alterações de duas linhas independentes de desenvolvimento, o svn precisará comparar as versões atuais de ambas e, em seguida, fazer uma comparação de três maneiras entre a última versão compartilhada e as duas versões principais. As linhas que aparecem alteradas em uma das cabeças, mas não na outra, podem ser facilmente resolvidas; linhas que se desviam exatamente da mesma maneira em ambas as cabeças são mais difíceis, mas geralmente são possíveis; linhas que se desviam de maneiras diferentes são o que faz o svn dizer "Não consigo entender isso, humano, por favor, resolva isso para mim."

Por outro lado, git e mercurial controlam os conjuntos de alterações em vez das versões. O repositório inteiro é uma árvore de conjuntos de alterações, cada um dependendo de um pai, onde um conjunto de alterações pai pode ter qualquer número de filhos e a raiz da árvore representa um diretório vazio. Em outras palavras, git / hg diz "primeiro eu não tinha nada, então esse patch foi aplicado, depois esse patch, etc.". Quando você precisa mesclar duas linhas de desenvolvimento, o git / hg não apenas sabe como são as cabeças atualmente e como era a última versão comum, mas também como a transição aconteceu, permitindo uma fusão muito mais inteligente.

Outra coisa que facilita a fusão em um DVCS é uma conseqüência indireta da separação dos conceitos de confirmação e envioe de permitir todos os tipos de mesclagens cruzadas entre dois clones do mesmo repositório a qualquer momento. Com o svn, as pessoas tendem a confirmar grandes conjuntos de alterações com alterações frequentemente não relacionadas, porque um commit também é uma atualização no repositório central que afeta todos os outros membros da equipe; se você cometer uma versão corrompida, todo mundo ficará bravo com você. Como a maioria das configurações envolve um servidor svn em rede, a confirmação também envolve o bombeamento de dados pela rede, o que significa que a confirmação introduz um atraso considerável no fluxo de trabalho (especialmente quando sua cópia de trabalho está desatualizada e você precisa puxar primeiro). Com o git e o mercurial, o commit ocorre localmente e, como ambos são muito eficientes no manuseio de sistemas de arquivos locais, geralmente termina instantaneamente. Como resultado, as pessoas (quando se acostumam) cometem pequenas alterações incrementais e, quando funciona, empurre uma dúzia ou mais comete de uma só vez. Então, quando chegar a hora da mesclagem, o SCM terá informações muito mais detalhadas e poderá executar um trabalho melhor na solução de conflitos de forma segura e automática.

E há os detalhes agradáveis ​​que tornam as coisas ainda mais fáceis:

  • Você pode ter várias cabeças e ainda assim se comprometer; diferente da subversão, você não precisa combinar puxar, atualizar e mesclar antes de cometer novamente - as várias cabeças permanecem assim até você optar por mesclar
  • Diretórios não são tratados especialmente; em vez disso, o caminho é considerado apenas um nome de arquivo grande e todos os seus diretórios precisam estar sempre na mesma revisão. Isso significa que você não pode executar o vodu de subversão em que as subpastas de um projeto estão em revisões diferentes, mas também significa que é menos provável que a cópia de trabalho se torne uma enorme bagunça quebrada incontrolável e, mais interessante, uma movimentação não é representada como uma exclusão -and-add (que quebraria totalmente em svn se não fosse pelos metadados de atualização), mas simplesmente como um renomeação; se você mover um arquivo, todo o seu histórico será preservado; a mesclagem pode até aplicar alterações ao arquivo movido que foram feitas em uma versão não movida do mesmo arquivo após a movimentação, em outra ramificação
  • Na maioria das vezes, você nem precisa se ramificar: basta clonar o repositório inteiro. A clonagem é barata, especialmente se for feita no mesmo sistema de arquivos, e se você decidir se livrar do clone, basta excluir o diretório em que ele vive e é isso. Você nem precisa usar hg ou git para isso.
  • Existem poucas (se houver) restrições sobre o que você pode mesclar. Você pode ter seis clones do mesmo repositório e mesclar (ou melhor, empurrar ou puxar; geralmente não é necessária uma mesclagem explícita) de A para B, depois C para B, depois B para D, depois C para D, B voltar para A, D para E, a qualquer momento e quantas vezes quiser.
  • Você pode testar uma mesclagem clonando um dos repositórios que deseja mesclar e puxando para o outro. Se ele faz o que você quer, você pode voltar ao alvo real; se não, você joga fora o clone e começa de novo.
tdammers
fonte
2
Devo mencionar algumas correções e adiciona respostas: 1. As revisões do SVN são globais por repositório , a revisão representa todos os arquivos no repositório em algum momento 2. A tecnologia de mesclagem é basicamente comum no SVN e no DVCS - se o arquivo nos arquivos de mesclagem alterou apenas o Da mesma forma , a mesclagem produzirá a mesma quantidade de conflitos para o SVN e DVCS - todos os SCMs ainda operam no nível de cadeia, não em um bloco lógico 3. As grandes confirmações no SVN não são resultado de fraqueza arquitetural, mas porque os usuários geralmente são idiotas preguiçosos - eles ignoram padrões básicos. Filial | obras de mesclagem no SVN, se / dev / cérebro e / dev / mãos trabalho
preguiçoso Badger
2
Parte 2: A mesclagem inteligente no DVCS ocorre principalmente porque, ao contrário do Subversion, eles rastreiam e manipulam movimentos | renomear arquivos e o SVN não faz isso, portanto - qualquer operação que processe o arquivo, alterada de um lado e renomeada em segundo, falhará. Ramificação com ramos e com clonagem são apenas diferentes estratégias de ramificação com os mesmos direitos para viver, o que usar "... depende de ..."
preguiçoso Badger
@LazyBadger: Au contraire. Subversion faz movimentos de pista / renomeações, o que provoca conflitos espúrias em parte porque é manipulação de renomeações em fusão é simplesmente buggy e em parte porque há casos de canto que são difíceis ou impossíveis de tratar corretamente. Mais tarde, é por isso que o git (e copiado pela Mercurial) por design não controla os renomeados e os adivinha ao mesclar. O que funciona bem se o conteúdo ainda é semelhante o suficiente para ser mesclado (que é quando você precisa) e não faz coisas tolas de outra maneira.
Jan Hudec
@JanHudec - desculpe, o SVN handle não se move | renomeia em uma ação atômica (maneira DVCS - "renomear"), mas como "delete + ...", assim - produz conflitos de árvore, onde isso não acontece no DVCS ( renomeação verdadeira) ) A trilha mercurial renomeia explicitamente ( hg mvou hg addremove --similarity...), enquanto o Git usa heurística, mas ambas tratam de renomeação . Posso ter conflito de árvore mesmo com uma diferença de 1 string nos arquivos mesclados! Você precisa reaprender alguns aspectos do Subversion, desculpe.
Lazy Badger
5
Agora estamos ficando bastante técnicos :-) As cópias de faixas do Subversion e Mercurial , não renomeadas. Ambos os sistemas rastreiam rename a bcomo copy a b; remove ae ambos fazem isso em uma confirmação atômica. A diferença no comportamento de mesclagem decorre da manipulação diferente de casos de canto e do Subversion, permitindo mais mesclagens que Mercurial e Git. Finalmente, o Git detecta renomeação na mesclagem e no tempo de log - estamos pensando em adicionar isso no Mercurial também.
Martin Geisler