Se os entendi corretamente (e estou longe de ser um especialista em cada um), eles fundamentalmente têm uma filosofia diferente. Eu usei o mercurial pela primeira vez por 9 meses. Agora eu usei o git para 6.
hg é um software de controle de versão. Seu principal objetivo é rastrear versões de um software.
O git é um sistema de arquivos baseado em tempo. Seu objetivo é adicionar outra dimensão a um sistema de arquivos. A maioria tem arquivos e pastas, o git adiciona tempo. O fato de funcionar de maneira impressionante como um VCS é um subproduto de seu design.
Em hg, há um histórico de todo o projeto que ele está sempre tentando manter. Por padrão, acredito que o hg deseja todas as alterações em todos os objetos por todos os usuários ao pressionar e puxar.
No git, há apenas um conjunto de objetos e esses arquivos de rastreamento (ramificações / cabeças) que determinam qual conjunto desses objetos representa a árvore de arquivos em um estado específico. Ao empurrar ou puxar, o git envia apenas os objetos necessários para os ramos específicos que você está empurrando ou puxando, que é um pequeno subconjunto de todos os objetos.
No que diz respeito ao git, não há "1 projeto". Você poderia ter 50 projetos no mesmo repositório e o git não se importaria. Cada um pode ser gerenciado separadamente no mesmo repositório e viver bem.
O conceito de Hg de ramificações é ramificações do projeto principal ou ramificações etc. O Git não tem esse conceito. Um ramo no git é apenas um estado da árvore, tudo é um ramo no git. Qual ramo é oficial, atual ou mais recente não tem significado no git.
Não sei se isso faz algum sentido. Se eu pudesse desenhar imagens, o hg pode ficar assim em que cada commit é umo
o---o---o
/
o---o---o---o---o---o---o---o
\ /
o---o---o
Uma árvore com uma única raiz e galhos saindo dela. Enquanto o git pode fazer isso, e muitas vezes as pessoas usam dessa maneira que não são aplicadas. Uma imagem do Git, se houver, poderia facilmente se parecer com isso
o---o---o---o---o
o---o---o---o
\
o---o
o---o---o---o
De fato, de certa forma, nem faz sentido mostrar ramificações no git.
Uma coisa que é muito confusa para a discussão: git e mercurial têm algo chamado "ramo", mas não são remotamente as mesmas coisas. Um ramo no mercurial ocorre quando há conflitos entre diferentes repositórios. Uma ramificação no git é aparentemente semelhante a um clone em hg. Mas um clone, embora possa dar um comportamento semelhante, definitivamente não é o mesmo. Considere-me tentar isso no git vs hg usando o repositório de cromo, que é bastante grande.
$ time git checkout -b some-new-branch
Switched to new branch 'some-new-branch'
real 0m1.759s
user 0m1.596s
sys 0m0.144s
E agora em hg usando clone
$ time hg clone project/ some-clone/
updating to branch default
29387 files updated, 0 files merged, 0 files removed, 0 files unresolved.
real 0m58.196s
user 0m19.901s
sys 0m8.957
Ambos são corridas quentes. Ou seja, eu os executei duas vezes e esta é a segunda execução. O clone hg é o mesmo que o git-new-workdir. Ambos formam um diretório de trabalho totalmente novo quase como se você tivesse digitado cp -r project project-clone
. Isso não é o mesmo que criar um novo ramo no git. É muito mais pesado. Se existe o equivalente verdadeiro da ramificação do git em hg, não sei o que é.
Eu entendo que, em algum nível, hg e git possam fazer coisas semelhantes. Nesse caso, ainda existe uma grande diferença no fluxo de trabalho para o qual eles levam. No git, o fluxo de trabalho típico é criar uma ramificação para cada recurso.
git checkout master
git checkout -b add-2nd-joypad-support
git checkout master
git checkout -b fix-game-save-bug
git checkout master
git checkout -b add-a-star-support
Isso acabou de criar três ramificações, cada uma baseada em uma ramificação chamada mestre. (Tenho certeza de que há alguma maneira no git de fazer essas 1 linha cada em vez de 2)
Agora, para trabalhar em um, eu apenas faço
git checkout fix-game-save-bug
e comece a trabalhar. Confirme coisas, etc. Alternar entre ramificações, mesmo em um projeto tão grande quanto o chrome, é quase instantâneo. Na verdade, eu não sei como fazer isso em hg. Não faz parte de nenhum tutorial que li.
Outra grande diferença. Palco do Git.
Git tem essa ideia de um estágio. Você pode pensar nisso como uma pasta oculta. Quando você confirma, apenas confirma o que está no palco, não as mudanças na sua árvore de trabalho. Isso pode parecer estranho. Se você deseja confirmar todas as alterações em sua árvore de trabalho, você git commit -a
adiciona todos os arquivos modificados ao estágio e os confirma.
Qual é o sentido do palco então? Você pode facilmente separar seus commits. Imagine que você editou joypad.cpp e gamesave.cpp e deseja confirmá-los separadamente
git add joypad.cpp // copies to stage
git commit -m "added 2nd joypad support"
git add gamesave.cpp // copies to stage
git commit -m "fixed game save bug"
O Git ainda possui comandos para decidir quais linhas específicas no mesmo arquivo você deseja copiar para o estágio, para que você possa dividir essas confirmações separadamente. Por que você gostaria de fazer isso? Como como commits separados, outros podem obter apenas os que desejam ou, se houver um problema, podem reverter apenas o commit que teve o problema.