Por que Git é Melhor que X

where "x" is one of
Este site está aqui porque parece que estou gastando muito tempo ultimamente defendendo os giteiros contra acusações de fazerem parte de um mero fã-clube, de serem maria-vai-com-as-outras. Então, aqui está porque as pessoas estão mudando de X para Git, e porque você deveria também. Basta clicar em uma razão para visualizá-la.
hg bzr svn perforce

Branches Locais Baratos

Provavelmente a funcionalidade mais atrativa do Git que realmente a torna diferente de praticamente todo outro SCM (Source Control Management, Sistemas de Gerenciamento de Fontes) é seu modelo de branches ("bifurcações", ou "galhos"). É completamente diferente de todos os outros modelos que estou comparando aqui, onde a maioria recomenda que o melhor branch é basicamente um clone do repositório em outro diretório.
Git não funciona dessa forma. Git permite a existência de múltiplos branches locais que podem ser inteiramente independentes de cada um e a criação, merges ("junções", ou "fusões") e deleção dessas linhas de desenvolvimento levam segundos.
Isso significa que você pode fazer coisas como:
  • Criar um branch para testar uma idéia, fazer commit algumas vezes, voltar para a partir de onde você fez o branch, aplicar um patch (conjunto de modificações), voltar para onde está experimentando, então fazer merge.
  • Ter um branch que sempre contém somente o que vai para produção, outro onde você faz merge do trabalho para testar e várias outras menores para atividades do dia a dia.
  • Criar novas branches para cada nova funcionalidade que estiver trabalhando, para que você possa mudar de uma para outra com facilidade, então deletar cada branch quando essa fizer merge dessa funcionalidade na linha principal.
  • Criar um branch para experimentar, descobrir que não vai funcionar e somente deletá-la, abandonando o trabalho - sem que ninguém veja isso (mesmo se você tiver trabalhado outras branches no meio do caminho).
branches flowchart
De forma importante, quando você dá push ("empurra") para um repositório remoto, você não precisa empurrar todos os seus branches. Você pode apenas compartilhar um de seus branches e não todos. Isso tende a liberar as pessoas para testar novas idéias sem se preocupar sobre ter um plano de como eles vão fazer merge ou compartilhar com os outros.
Você pode encontrar maneiras de fazer alguma coisa disso em outros sistemas, mas o trabalho envolvido é muito mais difícil e passível de erros. Git torna esse processo incrivelmente fácil e muda a maneira como a maioria dos desenvolvedores trabalhando quando aprendem.
jamis twitter trevorturk twitter thillerson twitter boblmartens twitter mathie twitter
svn perforce

Tudo é local

Isso é basicamente verdade de todos os SCMs distribuídos, mas em minha experiência muito mais com Git. Existe muito pouco fora de 'fetch', 'pull', 'push' que comunica de alguma maneira com qualquer coisa além do seu disco rígido.
Isso não só faz com que a maioria das operações seja mais rápida do que você deve estar acostumado, mas também lhe permite trabalhar em coisas quando está desconectado. Isso pode não soar grande coisa, mas eu sempre me surpreendo com a frequência com que eu de fato trabalho desconectado. Ser capaz de fazer branches, merges, commits e listar o histórico do seu projeto enquanto está no avião ou trem é muito produtivo.
local repo to remote repo flowchart
Mesmo no Mercurial, comandos comuns como 'incoming' e 'outgoing' conectam ao servidor, enquanto com o Git você pode fazer 'fetch' de todos os dados dos servidores antes de se desconectar e fazer comparações, merges e logs de dados que estão no servidor mas não nos seus branches locais ainda.
Isso significa que é muito fácil ter cópias não somente de seus branches, mas também dos branches de todo mundo que está trabalhando com você em seu repositório Git sem ter que bagunçar suas próprias coisas.
bzr svn perforce

Git é Rápido

Git é rápido. Todo mundo, mesmo os usuários mais pesados desses outros sistemas geralmente dão esse título ao Git. Comparado ao SVN e Perforce isso é óbvio, já que todas as operações são locais. Entretando, mesmo comparado com outros DSCMs, Git é muito rápido.
Parte disso provavelmente é porque ele foi construído para trabalhar com a kernel do Linux, o que significa que ele teve que lidar efetivamente com repositórios enormes desde o primeiro dia. Outra razão é que o Git é escrito em C, e ainda outra razão é que os desenvolvedores principais são, por minha experiência, muito muito preocupados com isso.
A seguir vários benchmarks que eu rodei em 3 cópias do código fonte do repositório do Django em 3 diferentes SCMs: Git, Mercurial e Bazaar. Eu também testei algumas dessas coisas no SVN, mas acredite, é muito lento - basicamente pegue os números do Bazaar e adicione a latência da rede...
init benchmarks add benchmarks status benchmarks diff benchmarks branching benchmarks
tag benchmarks log benchmarks large commit benchmarks small commit benchmarks
O resultado final é que para qualquer coisa, menos adicionar novos arquivos, Git foi o mais rápido. (Também em commits grandes, foi basicamente a mesma coisa que o Hg, mas o commit que eu testei foi tão grande que provavelmente ninguém fará nada parecido - em commits normais o Git é muito mais rápido).
Git Hg Bzr
Init 0.024s 0.059s 0.600s
Add 8.535s 0.368s 2.381s
Status 0.451s 1.946s 14.744s
Diff 0.543s 2.189s 14.248s
Tag 0.056s 1.201s 1.892s
Log 0.711s 2.650s 9.055s
Commit (Grande) 12.480s 12.500s 23.002s
Commit (Pequeno) 0.086s 0.517s 1.139s
Branch (Frio) 1.161s 94.681s 82.249s
Branch (Quente) 0.070s 12.300s 39.411s
Os números de branches frios e quentes são números da primeira e segunda vez que eu fiz branch de um repo - o segundo número sendo um branch com um cache de disco quente.
Deve ser notado que embora os números de 'add' sejam muito mais lentos, isso foi para uma operação enorme - mais de 2000 arquivos. Para a maioria das coisas que a maioria das pessoas faz no dia a dia, operações de adição (add) em qualquer desses sistemas vai tomar somente uma fração de segundo. Todas as outras operações testadas aqui (exceto para o grande commit, possivelmente) são mais indicativas das coisas que você realmente faz no dia a dia.
Esses números realmente não são difíceis de recriar, simplesmente clone o projeto Django em cada um dos sistemas e teste alguns dos mesmos comandos em cada um.
  • git clone git://github.com/brosner/django.git dj-git
  • hg clone http://hg.dpaste.com/django/trunk dj-hg
  • bzr branch lp:django dj-bzr
  • svn checkout http://code.djangoproject.com/svn/django/trunk dj-svn
svn

Git é Pequeno

Git é realmente bom em conservar espaço. Seu diretório Git vai (em geral) ser só um pouquinho maior que um checkout de SVN - em alguns casos de fato menor (aparentemente aqueles diretórios .svn podem ter muita coisa).
Os seguintes números foram tirados de clones do projeto Django de cada um de seus espelhos semi-oficiais de Git no mesmo ponto de histórico.
Git Hg Bzr Bzr* SVN
Só o Repo 24M 34M 45M 89M
Diretório Inteiro 43M 53M 64M 108M 61M
* o segundo número de Bzr é depois de rodar 'bzr pack', que eu imaginei que fosse torná-lo menor, mas acabou tornando-o muito, muito maior por alguma razão.
hg bzr svn perforce

A Área Intermediária

Diferente de outros sistemas, Git tem o que se chama "área intermediária" (também conhecida como staging ou index). Essa é uma área intermediária que você pode configurar como você quer que seu commit fique antes de fazê-lo.
A parte legal dessa área intermediária, e o que separa o Git de todas as outras ferramentas, é que você pode facilmente ir colocando seus arquivos nela à medida que for terminando e então fazer commit deles sem fazer commit de todos os arquivos modificados em seu diretório de trabalho, ou ter que listá-los na linha de comando durante o commit.
add commit workflow diagram
Isso também permite colocar partes de arquivos na área intermediária que foram modificadas, por exemplo para deixar para commit as mudanças que estão no topo do arquivo que está mexendo, mas não as mudanças de baixo.
Claro, Git torna muito fácil ignorar essa funcionalidade se você não quiser esse tipo de controle - apenas ponha um '-a' (all) no seu comando de commit.
commit only workflow diagram
svn perforce

Distribuído

Uma das funcionalidades mais legais de qualquer SCM Distribuído, Git incluso, é que ele é, claro, distribuído. Isso significa que em vez de fazer um "checkout" do topo atual do código fonte, você faz um "clone" do repositório inteiro.
Isso significa que mesmo que estiver usando um fluxo de trabalho centralizado, cada usuário tem o que é essencialmente um backup completo do servidor principal, e cada qual pode ser empurrado para substituir o servidor principal no evento de uma queda ou corrupção dos dados. Basicamente não existe ponto único de falha com Git a menos que só exista um ponto.
Isso não torna as coisas devagar também. Na média, um checkout de SVN é mais rápido do que qualquer um dos DSCMs, mas não muito. Além disso, dos DSCMs, o Git foi o mais rápido nos meus testes.
cloning benchmarks
Git 1m 59s
Hg 2m 24s
Bzr 5m 11s
SVN 1m 4s
svn perforce

Qualquer Fluxo de Trabalho

Uma das coisas fantásticas sobre Git é que por ele ser distribuído por natureza e ter um super sistema de branches, você pode facilmente implementar praticamente qualquer fluxo de trabalho que puder pensar com facilidade.

Fluxo de Trabalho Estilo Subversion

Um fluxo muito comum de Git, especialmente para pessoas transitando de um sistema centralizado, é um fluxo centralizado. Git não vai permitir que você de empurrar (push) se alguém empurrou desde a última fez que você puxou (fetch), então um modelo centralizado onde todos os desenvolvedores empurrar para o mesmo servidor funciona perfeitamente.
subversion-style workflow

Fluxo de Gerenciamento de Integração

Outro fluxo comum de Git é onde existe uma gestão de integração - uma única pessoa que faz commit ao repositório abençoado ('blessed'), e vários desenvolvedores que fazem clone desse repositório, empurram para seus repositórios independentes e pedem ao integrador para puxar suas mudanças. Esse é o modelo de desenvolvimento que você normalmente vê com projetos open source ou repositórios no GitHub.
integration manager workflow

Fluxos de Ditador e Tenentes

Para projetos maiores, você pode configurar seu desenvolvimento de maneira similar como a que a kernel do Linux roda, onde algumas pessoas são responsáveis por um sub-sistema específico do projeto (os 'tenentes') e fazem merge de todas as mudanças que tem a ver com esse sub-sistema. Então outro integrador (o 'ditador') pode puxar as mudanças de seus tenentes e empurrar para o repositório 'abençoado', e então todos fazem clone a partir dele novamente.
dictator and lieutenants workflow

Novamente, Git é inteiramente flexível sobre isso, então você pode misturar e comparar e encontrar o fluxo de trabalho que for melhor para você.
hg bzr svn perforce

GitHub

octocat
Eu posso ser suspeito aqui, já que trabalho para o GitHub, mas adicionei essa seção de qualquer forma porque muitas pessoas dizem que o próprio GitHub foi justamente porque escolheram Git.
GitHub é uma razão para usar Git para muitas pessoas porque é mais como uma rede social de código do que um site de hospedagem. As pessoas encontram outros desenvolvedores ou projetos similares às coisas que estão fazendo, e podem facilmente fazer forks (cópias dos repositórios) e contribuir, criando uma comunidade muito vibrante em torno do Git e dos projetos que as pessoas usam.
Existem outros serviços, tanto para Git quanto outros SCMs, mas poucos são orientados a usuários ou com objetivos sociais, e nenhum tem nada perto da quantidade de usuários. O aspecto social do GitHub é matador, e isso se soma a todas as funcionalidades listadas acima, tornando trabalhar com Git e GitHub uma grande combinação para desenvolvimento rápido de projetos open source.
Esse tipo de comunidade simplesmente não existe em nenhum outro tipo de SCM.
puls twitter twitter
perforce

Fácil de Aprender

Isso não costumava ser verdade - quando Git era mais novo, não era bem um SCM mas um conjunto de ferramentas que o permitia trabalhar com um sistema de arquivos versionados de maneira distribuída. Entretanto, hoje, o conjunto de comandos e a curva de aprendizagem do Git são muito similares de qualquer outro SCM, e mesmo melhor que alguns.
Já que isso é difícil de provar de maneira objetiva sem algum tipo de estudo, vou somente mostrar as diferenças entre o 'help' padrão do menu de comandos para Mercurial e Git. Eu grifei os comandos que são idênticos (ou quase) entre ambos. (Em Hg, se você digitar 'hg help', terá uma lista de uns 40 comandos).

Mercurial Help

add        add the specified files ...
annotate   show changeset informati...
clone      make a copy of an existi...
commit     commit the specified fil...
diff       diff repository (or sele...
export     dump the header and diff...
init       create a new repository ...
log        show revision history of...
merge      merge working directory ...
parents    show the parents of the ...
pull       pull changes from the sp...
push       push changes to the spec...
remove     remove the specified fil...
serve      export the repository vi...
status     show changed files in th...
update     update working directory

Git Help

add        Add file contents to the index
bisect     Find the change that introduce...
branch     List, create, or delete branches
checkout   Checkout a branch or paths to ...
clone      Clone a repository into a new ...
commit     Record changes to the repository
diff       Show changes between commits, ...
fetch      Download objects and refs from...
grep       Print lines matching a pattern
init       Create an empty git repository
log        Show commit logs
merge      Join two or more development h...
mv         Move or rename a file, a direc...
pull       Fetch from and merge with anot...
push       Update remote refs along with ...
rebase     Forward-port local commits to ...
reset      Reset current HEAD to the spec...
rm         Remove files from the working ...
show       Show various types of objects
status     Show the working tree status
tag        Create, list, delete or verify...
Antes do Git 1.6, todos os comandos do Git costumavam ficar no mesmo caminho que todos outros executávis, o que era muito confuso para as pessoas. Embora o Git ainda reconheça todos eles, o único comando no path agora é 'git'. Então, se você olhar para Mercurial ou Git, o Git tem um conjunto de comandos e sistema de ajuda praticamente igual - existe muito pouca diferença do ponto de vista inicial de interface hoje.
Atualmente é bem difícil argumentar que Mercurial ou Bazaar são mais fáceis de aprender do que Git.