Por um tempo agora eu tenho usado o subversion para meus projetos pessoais.
Cada vez mais, continuo ouvindo grandes coisas sobre Git e Mercurial e DVCS em geral.
Eu gostaria de dar uma guinada na coisa toda do DVCS, mas não estou muito familiarizado com nenhuma das opções.
Quais são algumas das diferenças entre Mercurial e Git?
Nota: Eu estou não tentando descobrir qual é o "melhor" ou mesmo que eu deveria começar. Estou procurando principalmente áreas-chave onde elas são semelhantes e onde são diferentes, porque estou interessado em saber como elas diferem em termos de implementação e filosofia.
Respostas:
Isenção de responsabilidade: Eu uso o Git, sigo o desenvolvimento do Git na lista de discussão do git e até contribuo um pouco para o Git (principalmente o gitweb). Conheço o Mercurial pela documentação e alguns pela discussão no canal IRR #revctrl no FreeNode.
Obrigado a todas as pessoas no canal #mercurial IRC que forneceram ajuda sobre o Mercurial para esta redação
Sumário
Aqui seria bom ter alguma sintaxe para a tabela, algo como na extensão PHPMarkdown / MultiMarkdown / Maruku do Markdown
.hgtags
arquivo com versão com regras especiais para tags por repositório e também suporta tags locais em.hg/localtags
; As tags Git são refs que residem norefs/tags/
espaço para nome e, por padrão, são seguidas automaticamente na busca e requerem envio explícito.Existem algumas coisas que diferem o Mercurial do Git, mas outras que os tornam semelhantes. Ambos os projetos tomam emprestado idéias um do outro. Por exemplo, o
hg bisect
comando no Mercurial (anteriormente chamado de extensão de bissetriz ) foi inspirado pelogit bisect
comando no Git, enquanto a ideia degit bundle
foi inspirada nohg bundle
.Estrutura do repositório, armazenando revisões
No Git, existem quatro tipos de objetos em seu banco de dados: objetos blob que contêm o conteúdo de um arquivo, objetos em árvore hierárquica que armazenam a estrutura de diretórios, incluindo nomes de arquivos e partes relevantes das permissões de arquivos (permissão executável para arquivos, sendo um link simbólico) , objeto de confirmação que contém informações de autoria, ponteiro para captura instantânea do estado do repositório na revisão representada por uma confirmação (por meio de um objeto em árvore do diretório principal do projeto) e referências a zero ou mais confirmações pai e marca objetos que referenciam outros objetos e podem ser assinado usando PGP / GPG.
O Git usa duas maneiras de armazenar objetos: formato livre , onde cada objeto é armazenado em um arquivo separado (esses arquivos são gravados uma vez e nunca modificados) e formato compactado , onde muitos objetos são armazenados compactados em delta em um único arquivo. A atomicidade das operações é fornecida pelo fato de que a referência a um novo objeto é gravada (atomicamente, usando o truque de criar + renomear) após a gravação de um objeto.
Os repositórios do Git requerem manutenção periódica usando
git gc
(para reduzir o espaço em disco e melhorar o desempenho), embora atualmente o Git faça isso automaticamente. (Este método fornece uma melhor compactação de repositórios.)Mercurial (tanto quanto eu o entendo) armazena o histórico de um arquivo em um registro de arquivos (juntos, eu acho, com metadados extras, como rastreamento de renomeação e algumas informações auxiliares); ele usa a estrutura plana chamada manifest para armazenar a estrutura do diretório e a estrutura chamada changelog que armazena informações sobre conjuntos de alterações (revisões), incluindo mensagem de confirmação e zero, um ou dois pais.
O Mercurial usa o diário de transações para fornecer atomicidade das operações e conta com o truncamento de arquivos para limpeza após operação com falha ou interrupção. Revlogs são apenas anexos.
Observando a estrutura do repositório no Git versus no Mercurial, pode-se ver que o Git se parece mais com um banco de dados de objetos (ou um sistema de arquivos endereçado a conteúdo) e o Mercurial mais como um banco de dados relacional de campo fixo tradicional.
Diferenças:
No Git, os objetos em árvore formam uma estrutura hierárquica ; no arquivo de manifesto Mercurial é estrutura plana . No objeto Blob Git, armazene uma versão do conteúdo de um arquivo; no Mercurial filelog armazena todo o histórico de um único arquivo (se não levarmos em conta aqui quaisquer complicações com renomeação). Isso significa que existem diferentes áreas de operações em que o Git seria mais rápido que o Mercurial, todas as outras coisas consideradas iguais (como mesclagens ou exibição do histórico de um projeto) e áreas em que o Mercurial seria mais rápido que o Git (como aplicação de patches ou exibição histórico de um único arquivo).Esse problema pode não ser importante para o usuário final.
Por causa da estrutura de registro fixo da estrutura do changelog do Mercurial , os commits no Mercurial podem ter apenas até dois pais ; commits no Git podem ter mais de dois pais (o chamado "polvo mesclado"). Embora você possa (em teoria) substituir a mesclagem de polvo por uma série de mesclagens com dois pais, isso pode causar complicações na conversão entre os repositórios Mercurial e Git.
Tanto quanto eu sei, o Mercurial não tem equivalente de tags anotadas (objetos de tag) do Git. Um caso especial de tags anotadas são tags assinadas (com assinatura PGP / GPG); O equivalente no Mercurial pode ser feito usando GpgExtension , cuja extensão está sendo distribuída junto com o Mercurial. Você não pode marcar objetos não confirmados no Mercurial como no Git, mas acho que isso não é muito importante (alguns repositórios git usam blob com tags para distribuir a chave pública do PGP e verificar as tags assinadas).
Referências: ramos e tags
No Git, as referências (ramificações, ramificações de rastreamento remoto e tags) residem fora do DAG de confirmações (como deveriam). Referências no
refs/heads/
espaço para nome ( ramificações locais ) apontam para confirmações e geralmente são atualizadas por "git commit"; eles apontam para a ponta (cabeça) do galho, é por isso que esse nome. As referências norefs/remotes/<remotename>/
espaço para nome ( ramificações de rastreamento remoto ) apontam para confirmação, seguem ramificações no repositório remoto<remotename>
e são atualizadas por "git fetch" ou equivalente. As referências norefs/tags/
namespace ( tags ) apontam geralmente para confirmações (tags leves) ou objetos de tag (tags anotadas e assinadas) e não devem ser alteradas.Tag
No Mercurial, você pode atribuir um nome persistente à revisão usando tag ; as tags são armazenadas de maneira semelhante aos padrões de ignorar. Isso significa que as tags visíveis globalmente são armazenadas em um
.hgtags
arquivo controlado por revisão no seu repositório. Isso tem duas conseqüências: primeiro, o Mercurial precisa usar regras especiais para esse arquivo para obter a lista atual de todas as tags e atualizar esse arquivo (por exemplo, ele lê a revisão confirmada mais recentemente do arquivo, a versão não registrada no momento); segundo, você precisa confirmar as alterações nesse arquivo para ter uma nova tag visível para outros usuários / outros repositórios (tanto quanto eu o entendo).O Mercurial também suporta tags locais , armazenadas em
hg/localtags
, que não são visíveis para outras pessoas (e, é claro, não são transferíveis)No Git, tags são referências fixas (constantes) nomeadas a outros objetos (geralmente objetos de tag, que por sua vez apontam para confirmações) armazenados no
refs/tags/
espaço para nome. Por padrão, ao buscar ou empurrar um conjunto de revisões, o git busca ou envia automaticamente tags que apontam para revisões sendo buscadas ou enviadas por push. No entanto, você pode controlar até certo ponto quais tags são buscadas ou enviadas por push.O Git trata tags leves (apontando diretamente para confirmações) e tags anotadas (apontando para objetos de tag, que contêm mensagem de tag que inclui opcionalmente assinatura PGP, que por sua vez apontam para confirmação) de maneira um pouco diferente, por exemplo, por padrão, considera apenas tags anotadas ao descrever confirma usando "git description".
O Git não possui um equivalente estrito de tags locais no Mercurial. No entanto, as práticas recomendadas do git recomendam configurar um repositório público vazio separado, no qual você envia alterações prontas e do qual outros clonam e buscam. Isso significa que as tags (e ramificações) que você não envia por push são privadas para o seu repositório. Por outro lado, você também pode usar um espaço para nome que não seja
heads
,remotes
outags
, por exemplo,local-tags
para tags locais.Opinião pessoal: na minha opinião, as tags devem residir fora do gráfico de revisão, pois são externas a ele (são indicadores do gráfico de revisões). As tags devem ser sem versão, mas transferíveis. A escolha da Mercurial de usar um mecanismo semelhante ao mecanismo para ignorar arquivos, significa que ele deve ser tratado
.hgtags
especialmente (o arquivo na árvore é transferível, mas comum é versionado), ou possui tags apenas locais (.hg/localtags
sem versão, intransferível).Ramos
Na filial local do Git (ponta da ramificação ou cabeça da ramificação) é uma referência nomeada a uma confirmação, na qual é possível aumentar novas confirmações. Ramificação também pode significar linha de desenvolvimento ativa, ou seja, todas as confirmações alcançáveis a partir da ponta da ramificação. As ramificações locais residem no
refs/heads/
espaço para nome, portanto, por exemplo, o nome completo da ramificação 'master' é 'refs / heads / master'.A ramificação atual no Git (ou seja, ramificação com check-out e ramificação para onde a nova consolidação irá) é a ramificação que é referenciada pela referência HEAD. Pode-se ter HEAD apontando diretamente para um commit, em vez de ser uma referência simbólica; esta situação de estar em uma ramificação anônima e sem nome é chamada HEAD desanexada ("ramificação git" mostra que você está em '(sem ramificação)').
No Mercurial, existem ramificações anônimas (cabeças de ramificação), e é possível usar marcadores (via extensão de marcador ). Essas ramificações de favoritos são puramente locais e esses nomes (até a versão 1.6) não são transferíveis usando o Mercurial. Você pode usar rsync ou scp para copiar o
.hg/bookmarks
arquivo em um repositório remoto. Você também pode usarhg id -r <bookmark> <url>
para obter o ID da revisão de uma dica atual de um marcador.Desde 1,6 marcadores podem ser empurrados / puxados. A página BookmarksExtension possui uma seção sobre Trabalhando com repositórios remotos . Há uma diferença em que os nomes de favoritos do Mercurial são globais , enquanto a definição de 'remoto' no Git descreve também o mapeamento de nomes de ramificações dos nomes no repositório remoto para os nomes das ramificações locais de rastreamento remoto; por exemplo,
refs/heads/*:refs/remotes/origin/*
mapeamento significa que é possível encontrar o estado da ramificação 'mestre' ('refs / heads / master') no repositório remoto no ramo de rastreamento remoto 'origin / master' ('refs / remotes / origin / master').O Mercurial também denominou ramificações nomeadas , em que o nome da ramificação é incorporado em uma confirmação (em um conjunto de alterações). Esse nome é global (transferido na busca). Esses nomes de filiais são permanentemente registrados como parte dos metadados do conjunto de alterações. Com o Mercurial moderno, você pode fechar o "ramo nomeado" e parar de gravar o nome do ramo. Neste mecanismo, as dicas dos galhos são calculadas em tempo real.
Os "ramos nomeados" do Mercurial deveriam, em minha opinião, ser chamados de " commit labels" , porque é o que são. Há situações em que "ramificação nomeada" pode ter várias dicas (vários commits sem filhos) e também pode consistir em várias partes disjuntas do gráfico de revisões.
Não há equivalente a essas "ramificações incorporadas" do Mercurial no Git; além disso, a filosofia do Git é que, embora se possa dizer que o ramo inclui algum commit, isso não significa que um commit pertence a algum branch.
Observe que a documentação do Mercurial ainda propõe o uso de clones separados (repositórios separados) pelo menos para ramificações de longa duração (ramificação única por fluxo de trabalho do repositório), também conhecida como ramificação por clonagem .
Ramos em empurrar
Mercurial por padrão empurra todas as cabeças . Se você deseja enviar uma única ramificação ( cabeçote único ), é necessário especificar a revisão da ponta da ramificação que deseja enviar. Você pode especificar a dica da ramificação pelo número da revisão (local para o repositório), pelo identificador da revisão, pelo nome do marcador (local para o repositório, não é transferido) ou pelo nome da ramificação incorporada (ramificação nomeada).
Pelo que entendi, se você enviar uma série de revisões que contêm commits marcados como estando em algum "ramo nomeado" na linguagem Mercurial, você terá esse "ramo nomeado" no repositório para o qual envia. Isso significa que os nomes dessas ramificações incorporadas ("ramificações nomeadas") são globais (com relação aos clones de determinado repositório / projeto).
Por padrão (sujeito à
push.default
variável de configuração), "git push" ou "git push < remote >" O Git enviaria ramificações correspondentes , ou seja, apenas as ramificações locais que já possuem seus equivalentes já presentes no repositório remoto que você envia. Você pode usar a--all
opção git-push ("git push --all") para enviar todos os branches , você pode usar "git push < remote > < branch >" para enviar um único ramo e usar "git push < remote > HEAD "para empurrar o ramo atual .Tudo acima pressupõe que o Git não está configurado em quais ramificações enviar por meio de
remote.<remotename>.push
variáveis de configuração.Ramos na busca
Nota: aqui eu uso a terminologia Git, em que "buscar" significa fazer o download de alterações do repositório remoto sem integrar essas alterações ao trabalho local. É isso que "
git fetch
" e "hg pull
" fazem.Se entendi corretamente, por padrão, o Mercurial busca todas as cabeças do repositório remoto, mas você pode especificar a ramificação a ser buscada via "
hg pull --rev <rev> <url>
" ou "hg pull <url>#<rev>
" para obter uma única ramificação . Você pode especificar <rev> usando o identificador de revisão, o nome "ramificação nomeada" (ramificação incorporada no log de alterações) ou o nome do marcador. No entanto, o nome do marcador (pelo menos atualmente) não é transferido. Todas as revisões de "ramificações nomeadas" que você recebe pertencem à transferência. "hg pull" armazena dicas de galhos que foram buscados como cabeças anônimas e sem nome.No Git, por padrão (para controle remoto 'origin' criado por "git clone" e para controles remotos criados usando "git remote add") "
git fetch
" (ou "git fetch <remote>
") obtém todas as ramificações do repositório remoto (dorefs/heads/
espaço para nome) e as armazena emrefs/remotes/
namespace. Isso significa, por exemplo, que a ramificação denominada 'mestre' (nome completo: 'refs / heads / master') na 'origem' remota seria armazenada (salva) como ramificação de rastreamento remoto 'origem / mestre' (nome completo: 'refs / controles remotos / origem / mestre ').Você pode buscar uma única ramificação no Git usando
git fetch <remote> <branch>
- O Git armazenaria ramificações solicitadas em FETCH_HEAD, que é algo semelhante às cabeças sem nome do Mercurial.Esses são apenas exemplos de casos padrão da poderosa sintaxe refspec Git: com refspecs, você pode especificar e / ou configurar quais ramificações deseja buscar e onde armazená-las. Por exemplo, o caso "buscar todas as ramificações" padrão é representado por '+ refs / heads / *: refs / remotes / origin / *' curinga refspec, e "buscar uma ramificação única" é uma abreviação de 'refs / heads / <branch>:' . Refspecs são usados para mapear nomes de ramificações (refs) no repositório remoto para nomes de refs locais. Mas você não precisa saber (muito) sobre refspecs para poder trabalhar efetivamente com o Git (graças principalmente ao comando "git remote").
Opinião pessoal: Eu pessoalmente acho que "ramificações nomeadas" (com nomes de ramificações incorporadas nos metadados do conjunto de alterações) no Mercurial são um design equivocado com seu namespace global, especialmente para um sistema de controle de versão distribuído . Por exemplo, vamos considerar o caso em que Alice e Bob têm "ramificação nomeada" denominada 'for-joe' em seus repositórios, ramificações que não têm nada em comum. No repositório de Joe, no entanto, esses dois ramos seriam maltratados como um único ramo. Então, de alguma forma, você criou uma convenção que protege contra conflitos de nome de filial. Isso não é problema com o Git, onde, no repositório de Joe, o ramo 'for-joe' de Alice seria 'alice / for-joe', e de Bob seria 'bob / for-joe'.
Atualmente, os "ramos de favoritos" da Mercurial não possuem mecanismo de distribuição dentro do núcleo.
Diferenças:
Esta área é uma das principais diferenças entre Mercurial e Git, como James Woodyatt e Steve Losh disseram em suas respostas. Mercurial, por padrão, usa linhas de código leves anônimas, que em sua terminologia são chamadas de "cabeças". O Git usa ramificações nomeadas leves, com mapeamento injetivo para mapear nomes de ramificações no repositório remoto para nomes de ramificações de rastreamento remoto. O Git "força" você a nomear ramificações (bem, com exceção de ramificação única sem nome, situação chamada HEAD desanexada), mas acho que isso funciona melhor com fluxos de trabalho com ramificação pesada, como fluxo de trabalho de ramificação de tópico, significando várias ramificações no paradigma de repositório único.
Revisões de nomeação
No Git, existem muitas maneiras de nomear revisões (descritas, por exemplo, na página de manual git rev-parse ):
^
parâmetro de sufixo para revisão significa o primeiro pai de um objeto de confirmação,^n
significa o nono pai de um commit de mesclagem. Um sufixo~n
para o parâmetro de revisão significa o nono-antepassado de um commit na linha direta do primeiro pai. Esses sufixos podem ser combinados, para formar um especificador de revisão seguindo o caminho de uma referência simbólica, por exemplo, 'pu ~ 3 ^ 2 ~ 3'Também existem especificadores de revisão envolvendo reflog, não mencionados aqui. No Git, cada objeto, seja ele commit, tag, tree ou blob, tem seu identificador SHA-1; existe uma sintaxe especial como, por exemplo, 'next: Documentation' ou 'next: README' para se referir à árvore (diretório) ou blob (conteúdo do arquivo) na revisão especificada.
O Mercurial também possui várias maneiras de nomear conjuntos de alterações (descritos, por exemplo, na página de manual hg ):
Diferenças
Como você pode ver nas listas acima, o Mercurial oferece números de revisão, locais para o repositório, enquanto o Git não. Por outro lado, o Mercurial oferece compensações relativas apenas de 'tip' (ramificação atual), local para o repositório (pelo menos sem ParentrevspecExtension ), enquanto o Git permite especificar qualquer confirmação após qualquer dica.
A revisão mais recente é denominada HEAD no Git e "tip" no Mercurial; não há revisão nula no Git. Tanto o Mercurial quanto o Git podem ter muitas raízes (podem ter mais de um commit sem pai; isso geralmente é resultado da junção de projetos anteriormente separados).
Veja também: Muitos tipos diferentes de especificadores de revisões no blog de Elijah (newren).
Opinião pessoal: acho que os números das revisões são superestimados (pelo menos no desenvolvimento distribuído e / ou histórico não-linear / ramificado). Primeiro, para um sistema de controle de versão distribuído, eles precisam ser locais para o repositório ou exigir o tratamento de algum repositório de maneira especial como uma autoridade central de numeração. Segundo, projetos maiores, com histórico mais longo, podem ter um número de revisões no intervalo de 5 dígitos, oferecendo apenas uma pequena vantagem sobre os identificadores de revisão reduzidos para 6-7 caracteres e implicando uma ordem estrita, enquanto as revisões são apenas parcialmente encomendadas (quero dizer aqui que as revisões n e n + 1 não precisam ser pai e filho).
Intervalos de revisão
No Git, os intervalos de revisão são topológicos . A
A..B
sintaxe comumente vista , que para o histórico linear significa o intervalo de revisão começando em A (mas excluindo A) e terminando em B (ou seja, o intervalo é aberto a partir de baixo ), é uma abreviação ("açúcar sintático") para^A B
, o que, para comandos que atravessam o histórico, significa tudo confirma acessível a partir de B, excluindo os acessíveis a partir de A. Isso significa que o comportamento doA..B
intervalo é totalmente previsível (e bastante útil), mesmo que A não seja ancestral de B:A..B
significa intervalo de revisões do ancestral comum de A e B (base de mesclagem ) à revisão B.No Mercurial, os intervalos de revisão são baseados no intervalo dos números de revisão . O intervalo é especificado usando a
A:B
sintaxe e, ao contrário do intervalo do Git, atua como um intervalo fechado . Também o intervalo B: A é o intervalo A: B em ordem inversa, o que não é o caso do Git (mas veja a nota abaixo naA...B
sintaxe). Mas essa simplicidade tem um preço: o intervalo de revisão A: B só faz sentido se A for ancestral de B ou vice-versa, ou seja, com história linear; caso contrário (acho que), o intervalo é imprevisível e o resultado é local no repositório (porque os números de revisão são locais no repositório).Isso é corrigido com o Mercurial 1.6, que possui um novo intervalo de revisão topológica , em que 'A..B' (ou 'A :: B') é entendido como o conjunto de conjuntos de alterações que são descendentes de X e ancestrais de Y. Isso é , Eu acho, equivalente a '--ancestry-path A..B' no Git.
Git também possui notação
A...B
para diferença simétrica de revisões; significaA B --not $(git merge-base A B)
, o que significa que todos os commits acessíveis a partir de A ou B, mas excluindo todos os commits acessíveis a partir de ambos (acessíveis a partir de ancestrais comuns).Renomeia
O Mercurial usa o rastreamento de renomeação para lidar com as renomeações de arquivos. Isso significa que as informações sobre o fato de um arquivo ter sido renomeado são salvas no momento da confirmação; no Mercurial, essas informações são salvas no formulário "diff aprimorado" nos metadados do registro de arquivos (revogação de arquivos). A conseqüência disso é que você precisa usar
hg rename
/hg mv
... ou precisa se lembrar de executarhg addremove
para fazer a detecção de renomeação baseada em similaridade.O Git é único entre os sistemas de controle de versão, pois usa a detecção de renomeação para lidar com as renomeações de arquivos. Isso significa que o fato de o arquivo ter sido renomeado é detectado no momento em que é necessário: ao fazer uma mesclagem ou ao mostrar um diff (se solicitado / configurado). Isso tem a vantagem de renomear o algoritmo de detecção e pode não ser congelado no momento da confirmação.
O Git e o Mercurial requerem o uso da
--follow
opção para seguir as renomeações ao mostrar o histórico de um único arquivo. Ambos podem seguir os renomeamentos ao mostrar o histórico em linha de um arquivo emgit blame
/hg annotate
.No Git, o
git blame
comando é capaz de seguir o movimento do código, também movendo (ou copiando) o código de um arquivo para outro, mesmo que o movimento do código não faça parte da renomeação de arquivo saudável. Até onde eu sei, esse recurso é exclusivo do Git (no momento da redação, outubro de 2009).Protocolos de rede
O Mercurial e o Git têm suporte para buscar e enviar para repositórios no mesmo sistema de arquivos, onde a URL do repositório é apenas um caminho do sistema de arquivos para o repositório. Ambos também têm suporte para buscar arquivos de pacote configurável .
Suporte mercurial buscando e enviando via SSH e via protocolos HTTP. Para o SSH, é necessário ter uma conta shell acessível na máquina de destino e uma cópia do hg instalada / disponível. Para acesso HTTP, o
hg-serve
script Mercurial CGI ou em execução é necessário e o Mercurial precisa ser instalado na máquina do servidor.O Git suporta dois tipos de protocolos usados para acessar o repositório remoto:
git-daemon
), exigem a instalação do git no servidor. A troca nesses protocolos consiste em cliente e servidor negociando sobre quais objetos eles têm em comum e, em seguida, gerando e enviando um pacote. O Git moderno inclui suporte ao protocolo HTTP "inteligente".git update-server-info
(geralmente executadas a partir de um gancho) ) A troca consiste em o cliente percorrer a cadeia de consolidação e fazer o download de objetos e arquivos de pacotes soltos, conforme necessário. A desvantagem é que ele baixa mais do que o estritamente necessário (por exemplo, no caso de canto, quando há apenas um único pacote, ele seria baixado inteiro, mesmo ao buscar apenas algumas revisões), e pode exigir muitas conexões para ser concluído.Estendendo: capacidade de script vs extensões (plug-ins)
O Mercurial é implementado em Python , com alguns códigos principais escritos em C para desempenho. Ele fornece API para escrever extensões (plugins) como uma maneira de adicionar recursos extras. Algumas funcionalidades, como "ramificações de favoritos" ou revisões de assinatura, são fornecidas em extensões distribuídas com o Mercurial e requerem a ativação.
O Git é implementado nos scripts C , Perl e shell . O Git fornece muitos comandos de baixo nível ( encanamento ) adequados para uso em scripts. A maneira usual de introduzir um novo recurso é gravá-lo como Perl ou shell script, e quando a interface do usuário estabiliza, reescreva-o em C para desempenho, portabilidade e, no caso de shell script, evitando casos de canto (esse procedimento é chamado de builtinification ).
O Git confia e é construído em torno dos formatos [repositório] e protocolos [rede]. Em vez de ligações de idiomas, há reimplementações (parciais ou completas) do Git em outros idiomas (alguns deles são parcialmente reimplementações e parcialmente wrappers em torno dos comandos git): JGit (Java, usado por EGit, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), git # (C #).
TL; DR
fonte
Eu acho que você pode ter uma ideia de como esses sistemas são semelhantes ou diferentes ao gravar esses dois vídeos:
Linus Torvalds no Git ( http://www.youtube.com/watch?v=4XpnKHJAok8 )
Bryan O'Sullivan no Mercurial ( http://www.youtube.com/watch?v=JExtkqzEoHY )
Ambos são muito semelhantes em design, mas muito diferentes em implementações.
Eu uso o Mercurial. Tanto quanto eu entendo o Git, uma coisa importante é que o git é diferente: ele rastreia o conteúdo dos arquivos em vez dos próprios arquivos. Linus diz que, se você mover uma função de um arquivo para outro, o Git mostrará o histórico dessa única função ao longo da movimentação.
Eles também dizem que o git é mais lento em relação ao HTTP, mas tem seu próprio protocolo de rede e servidor.
O Git funciona melhor como um cliente espesso SVN do que o Mercurial. Você pode puxar e enviar contra um servidor SVN. Essa funcionalidade ainda está em desenvolvimento no Mercurial
Tanto o Mercurial quanto o Git têm ótimas soluções de hospedagem disponíveis na Web (BitBucket e GitHub), mas o Google Code suporta apenas o Mercurial. A propósito, eles têm uma comparação muito detalhada do Mercurial e do Git para decidir qual deles oferecer suporte ( http://code.google.com/p/support/wiki/DVCSAnalysis ). Tem muitas informações boas.
fonte
Escrevi uma entrada de blog sobre os modelos de ramificação do Mercurial há algum tempo e incluí comparações com o modelo de ramificação do git. Talvez você ache interessante: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/
fonte
Eu uso os dois regularmente. A principal diferença funcional está na maneira como os nomes Git e Mercurial se ramificam nos repositórios. Com o Mercurial, os nomes das ramificações são clonados e puxados junto com seus conjuntos de alterações. Quando você adiciona alterações a uma nova ramificação no Mercurial e envia para outro repositório, o nome da ramificação é enviado ao mesmo tempo. Portanto, os nomes das filiais são mais ou menos globais no Mercurial, e você precisa usar a extensão Bookmark para ter nomes leves apenas locais (se você quiser; o Mercurial, por padrão, usa linhas de código leves anônimas, que em sua terminologia são chamados "cabeças"). No Git, os nomes das ramificações e seu mapeamento injetivo para ramificações remotas são armazenados localmente e você deve gerenciá-los explicitamente, o que significa saber como fazer isso.
Como outros observarão aqui, há muitas e pequenas diferenças. A coisa com os galhos é o grande diferencial.
fonte
Dê uma olhada no Git vs. Mercurial: relaxe no blog de Patrick Thomson, onde ele escreve:
Git é MacGyver , Mercurial é James Bond
Observe que esta postagem do blog é de 7 de agosto de 2008 e os dois SCM melhoraram muito desde então.
fonte
Mercurial é quase totalmente escrito em python. O núcleo do Git é escrito em C (e deve ser mais rápido que o Mercurial) e as ferramentas escritas em sh, perl, tcl e usa utilitários GNU padrão. Portanto, ele precisa trazer todos esses utilitários e intérpretes para um sistema que não os contenha (por exemplo, Windows).
Ambos suportam o trabalho com o SVN, embora o suporte ao AFAIK svn esteja quebrado para o git no Windows (pode ser que eu seja apenas azarado / coxo, quem sabe). Também existem extensões que permitem interoperar entre git e Mercurial.
O Mercurial possui uma ótima integração com o Visual Studio . Na última vez que verifiquei, o plugin para Git estava funcionando, mas extremamente lento.
Os conjuntos de comandos básicos são muito semelhantes (init, clone, add, status, commit, push, pull etc.). Portanto, o fluxo de trabalho básico será o mesmo. Além disso, existe um cliente semelhante ao TortoiseSVN para ambos.
As extensões do Mercurial podem ser escritas em python (sem surpresa!) E, para o git, podem ser escritas em qualquer forma executável (binário executável, shell script etc). Algumas extensões são muito poderosas, como
git bisect
.fonte
Se você precisar de um bom suporte do Windows, poderá preferir o Mercurial. O TortoiseHg (plugin do Windows Explorer) consegue oferecer uma interface gráfica simples de usar para uma ferramenta bastante complexa. Como estado aqui, você também terá um plug-in do Visual Studio . No entanto, da última vez que tentei, a interface SVN não funcionou tão bem no Windows.
Se você não se importa com a interface da linha de comando, eu recomendaria o Git. Não por razões técnicas, mas por razões estratégicas. A taxa de adoção do git é muito maior. Veja quantos projetos de código aberto famosos estão mudando de cvs / svn para Mercurial e quantos estão mudando para Git. Veja quantos fornecedores de hospedagem de código / projeto você pode encontrar com suporte ao git em comparação com a hospedagem Mercurial.
fonte
Depois de ler tudo sobre o Mercurial, é mais fácil (o que eu ainda acredito, depois que toda a comunidade da Internet é de opinião), quando comecei a trabalhar com o Git e o Mercurial, senti que o Git é relativamente mais simples para me adaptar (comecei Mercurial com TortoiseHg) ao trabalhar na linha de comando, principalmente porque os comandos git foram nomeados adequadamente de acordo com mim e são menos numerosos. O Mercurial possui nomes diferentes para cada comando que executa um trabalho distinto, enquanto os comandos Git podem ser multiuso de acordo com a situação (por exemplo,
checkout
) Embora o Git fosse mais difícil na época, agora a diferença não é substancial. YMMV .. Com um bom cliente GUI como o TortoiseHg, é verdade que era muito mais fácil trabalhar com o Mercurial e não precisava me lembrar dos comandos um pouco confusos. Não vou detalhar como cada comando para a mesma ação variou, mas aqui estão duas listas abrangentes: 1 do próprio site da Mercurial e e2 da wikivs .O Git salva internamente um registro de todas as versões de arquivos confirmados, enquanto o Hg salva apenas os conjuntos de alterações que podem ter uma área menor. O Git facilita a alteração da história em comparação com o Hg, mas, novamente, é um recurso de ódio ou amor. Eu gosto de Hg para o primeiro e Git para o segundo.
O que sinto falta no Hg é o recurso do submódulo do Git. Hg tem subrepos, mas esse não é exatamente o submódulo Git.
O ecossistema em torno dos dois também pode influenciar a escolha de alguém: o Git precisa ser mais popular (mas isso é trivial), o Git tem o GitHub, enquanto o Mercurial tem o BitBucket , o Mercurial tem o TortoiseHg, para o qual eu não vi um equivalente tão bom para o Git.
Cada um tem suas vantagens e desvantagens, com um deles que você não vai perder.
fonte
Confira o post de Scott Chacon há algum tempo.
Eu acho que o git tem uma reputação de ser "mais complicado", embora na minha experiência não seja mais complicado do que precisa ser. Na IMO, o modelo git é muito mais fácil de entender (as tags contêm confirmações (e ponteiros para zero ou mais confirmações pai) contêm árvores contêm blobs e outras árvores ... concluídas).
Não é apenas minha experiência que o git não é mais confuso do que mercurial. Eu recomendo ler novamente este post de Scott Chacon sobre o assunto.
fonte
.hgtags
quando faz o check-out da revisão 1.0. No entanto, você não precisa olhar para dentro.hgtags
e verá quehg tags
ainda lista todas as tags. Além disso, esse comportamento é uma consequência simples do armazenamento de tags em um arquivo controlado por versão - novamente o modelo é fácil de entender e muito previsível .Eu uso o Git há pouco mais de um ano no meu trabalho atual e, antes disso, usei o Mercurial por um pouco mais de um ano no meu trabalho anterior. Vou fornecer uma avaliação da perspectiva do usuário.
Primeiro, ambos são sistemas de controle de versão distribuídos. Os sistemas de controle de versão distribuído requerem uma mudança de mentalidade em relação aos sistemas de controle de versão tradicionais, mas na verdade funcionam muito melhor de várias maneiras, quando os entendemos. Por esse motivo, considero o Git e o Mercurial muito superiores ao Subversion, Perforce etc. A diferença entre os sistemas de controle de versão distribuído e os sistemas tradicionais de controle de versão é muito maior que a diferença entre o Git e o Mercurial.
No entanto, também existem diferenças significativas entre o Git e o Mercurial que tornam cada um mais adequado ao seu próprio subconjunto de casos de uso.
Mercurial é mais simples de aprender. Cheguei ao ponto em que raramente tinha que me referir à documentação ou anotações após algumas semanas de uso do Mercurial; Ainda tenho que me referir às minhas anotações regularmente com o Git, mesmo depois de usá-lo por um ano. Git é consideravelmente mais complicado.
Isso ocorre em parte porque o Mercurial é simplesmente mais limpo. Você raramente precisa ramificar manualmente no Mercurial; O Mercurial criará uma filial anônima automaticamente para você, se e quando você precisar. A nomenclatura mercurial é mais intuitiva; você não precisa se preocupar com a diferença entre "buscar" e "puxar", como faz com o Git. Mercurial é um pouco menos buggy. Existem problemas de distinção entre maiúsculas e minúsculas nos nomes de arquivos que costumavam causar problemas ao enviar projetos entre plataformas com Git e Mercurial; isso foi corrigido no Mercurial há algum tempo, enquanto não havia sido corrigido no Git pela última vez que verifiquei. Você pode informar ao Mercurial sobre renomeação de arquivos; com o Git, se ele não detectar a renomeação automaticamente - uma proposta muito acertada ou perdida na minha experiência - a renomeação não poderá ser rastreada.
A outra razão para a complicação adicional do Git, no entanto, é que muito disso é necessário para suportar recursos e energia adicionais. Sim, é mais complicado lidar com ramificações no Git - mas, por outro lado, depois de ter as ramificações, não é muito difícil fazer coisas com essas ramificações que são praticamente impossíveis no Mercurial. Rebasear ramificações é uma dessas coisas: você pode mover sua ramificação para que sua base, em vez de ser o estado do tronco quando você ramificou, seja o estado do tronco agora; isso simplifica bastante o histórico da versão quando há muitas pessoas trabalhando na mesma base de código, já que cada um dos impulsos no tronco pode parecer sequencial, em vez de entrelaçado. Da mesma forma, é muito mais fácil recolher vários commit no seu branch em um único commit,
Por fim, acho que a escolha entre Mercurial e Git deve depender do tamanho dos seus projetos de controle de versão, medidos em termos do número de pessoas trabalhando neles simultaneamente. Se você tem um grupo de uma dúzia ou mais trabalhando em um único aplicativo da web monolítico, por exemplo, as ferramentas mais poderosas de gerenciamento de filiais do Git o tornarão um ajuste muito melhor para o seu projeto. Por outro lado, se sua equipe estiver desenvolvendo um sistema distribuído heterogêneo, com apenas um ou dois desenvolvedores trabalhando em um componente de cada vez, o uso de um repositório Mercurial para cada um dos projetos de componentes permitirá que o desenvolvimento prossiga de maneira mais suave com menos sobrecarga de gerenciamento de repositório.
Conclusão: se você tem uma grande equipe desenvolvendo um único aplicativo enorme, use o Git; se seus aplicativos individuais forem pequenos, com qualquer escala proveniente do número e não do tamanho desses aplicativos, use o Mercurial.
fonte
Uma diferença totalmente não relacionada aos DVCSs:
O Git parece ser muito popular entre os desenvolvedores C. O Git é o repositório de fato do Kernel Linux e esse pode ser o motivo pelo qual ele é tão popular entre os desenvolvedores C. Isto é especialmente verdade para aqueles que têm o luxo de trabalhar apenas no mundo Linux / Unix.
Os desenvolvedores de Java parecem preferir o Mercurial ao invés do Git. Há possivelmente duas razões para isso: uma é que vários projetos Java muito grandes estão hospedados no Mercurial, incluindo o próprio JDK. Outra é que a estrutura e a documentação limpa do Mercurial atraem pessoas provenientes do campo Java, enquanto essas pessoas acham o Git inconsistente nos nomes dos comandos wrt e carecem de documentação. Não estou dizendo que isso seja verdade, estou dizendo que as pessoas se acostumaram com algo do seu habitat habitual e então tendem a escolher o DVCS a partir disso.
Os desenvolvedores de Python favorecem quase exclusivamente o Mercurial, eu diria. Na verdade, não há nenhuma razão racional para isso além do fato de o Mercurial ser baseado em Python. (Também uso o Mercurial e realmente não entendo por que as pessoas se preocupam com a linguagem de implementação do DVCS. Não entendo uma palavra do Python e se não fosse pelo fato de estar listado em algum lugar é baseado em Python, então eu não saberia).
Eu não acho que você possa dizer que um DVCS se encaixa em um idioma melhor que outro, então você não deve escolher isso. Mas, na realidade, as pessoas escolhem (parcialmente) com base em quais DVCS ficam mais expostos como parte de sua comunidade.
(não, não tenho estatísticas de uso para fazer backup de minhas reivindicações acima .. tudo é baseado na minha própria subjetividade)
fonte