Futuro do Gerenciamento de Software: DVCS
Qualquer um que se entitule um profissional em desenvolvimento de software utiliza algum repositório de versionamento de código. É inevitável, mesmo quando se trabalha sozinho, para não se sentir inseguro sem um repositório onde seu trabalho é gerenciado.
Existem dezenas de produtos que fazem esse trabalho, incluindo o antigo CVS, seu sucessor Subversion (SVN), Rational ClearCase, Microsoft Visual Source Safe e outros. Esses sistemas tem uma coisa em comum: sua natureza centralizada. Existe um servidor, vários desenvolvedores necessariamente sincronizados com esse servidor, alguns com permissão apenas de leitura e um controle rígido no fluxo de código.
Trocar um pelo outro não é uma mudança tão grande assim no fluxo de trabalho em geral. Esse tipo de sistema possui um grande calcanhar de aquiles: sua natureza centralizada. O servidor central é o mestre do seu código. Os desenvolvedores tem apenas as últimas versões atualizadas do código em sua máquina e nenhuma memória do histórico completo do projeto.
Perca o servidor e você perde todo seu histórico. Pior: você só consegue trabalhar se estiver online, se estiver offline se tornará muito improdutivo pela impossibilidade de realizar um ‘commit’ ao servidor. Pior ainda: se mudar de idéia no meio do desenvolvimento é um jogo de tudo ou nada: ou você retorna ao último commit (commit = escrita no repositório) que baixou do servidor ou manualmente reedita seus arquivos até o meio do caminho onde queria. Pior do pior ainda: comece a usar branches (galhos de desenvolvimento paralelo no mesmo código) no seu servidor e terá uma dor de cabeça sem tamanho para conseguir mesclar mudanças com seu tronco principal de desenvolvimento. Por isso mesmo pouca gente usa branches em sistemas centralizados e os que usam dependem de pessoas especializadas em cuidar dos problemas que ele apresenta.
Isso inibe completamente o trabalho de um programador. Um bom programador precisa testar, precisa experimentar, precisa fazer provas de conceito. Assim como qualquer bom artista, ele precisa ser capaz de rabiscar suas idéias, e até mesmo mudar de idéia no meio do caminho sem problemas. Com sistemas centralizados e restritivos você é praticamente obrigado a uma cultura de acertar da primeira vez, porque erros custam caro. E em consequência, o programador experimenta cada vez menos, tornando-se menos e menos produtivo e desmotivado. É quando programar se torna ‘apenas mais um emprego’ e não é mais divertido como antes, sem repositório algum.
Existe solução aos sistemas centralizados de versionamento de código? Com certeza sim. Continue lendo este artigo.
DVCS - Distributed Version Control Systems
A resposta se chama DVCS - ou Sistemas Distribuídos de Controle de Versão - trata-se de um paradigma completamente diferente. Para entender a importância de redes distribuídas de escala livre (free scale networks) recomendo a leitura do excelente livro de Albert-laszlo Barabasi - Linked: The New Science of Networks. Numa explicação bastante simplificada minha, imagine uma rede em forma de estrela: com um ponto central e diversos nós ligados diretamente a esse centro. Elimine o nó central e toda a rede se desintegra.
Agora imagine redes distribuídas em escala livre seguindo uma Lei Potencial de Distribuição . É uma rede que não tem ponto único de falha e por isso é muito resistente a panes e ataques. Por acaso é exatamente como funciona a Internet. E não só isso: na natureza diversas redes seguem exatamente essa distribuição e por isso são tão resistentes. Um exemplo: pegue a cadeia alimentar de um certo ambiente. Essas redes não se destróem apenas porque uma das espécies no meio da rede é extinta. É preciso um ataque em múltiplos nós para que ela entre em colapso. Nossa amizades funcionam assim, a economia, enfim, todas as redes sólidas que imaginar seguem o mesmo conceito.
Desenvolvimento de software segue um padrão parecido: você tem código e desenvolvedores, interligados. Porém, em sistemas centralizados o potencial dessa rede permanece sempre restrito e artificialmente limitado. Seguindo o pensamento do The Long Tail, de Chris Anderson, é o efeito de se restringir somente à cabeça da cauda - o efeito “estante de supermercado” - limitando o potencial da Cauda Longa do desenvolvimento de software.
Entrem os repositórios de controle de versionamento distribuídos. A palavra-chave é distribuído. Diversos produtos - principalmente no mundo open source - cobrem esse problema. Existe o Bazaar, escrito em Python, que é usado pela Canonical para desenvolver o Ubuntu Linux. Existe o Mercurial, escrito em Python e é usado em alguns projetos da Sun e, o assunto deste artigo, existe o Git. Escrito em C, com autoria inicial de ninguém menos que o próprio Linus Torvalds e criado com o objetivo de resolver o monstruoso problema de gerenciar o desenvolvimento do kernel do Linux, com dezenas de milhares de desenvolvedores espalhados pelo mundo todo em um desenvolvimento super-ativo e intenso.
Não existe um ponto central obrigatório. Você pode “eleger” um hub mais importante. Mas qualquer nó dessa rede pode imediatamente assumir esse papel sem prejuízos para a rede.
Você pode continuar fazendo commits para o hub eleito, mas se quiser pode ignorá-lo completamente: você e um amigo podem desenvolver juntos e isolados do resto da equipe, cada um sincronizando com o repositório local do outro. Ao final apenas um deles pode empurrar os commits ao hub eleito.
O mais importante: o repositório é sempre local à máquina do desenvolvedor. Ele tem à sua imediata disposição o repositório completo! Com todo o histórico de desenvolvimento desde o primeiro commit do primeiro desenvolvedor, e você tem liberdade de navegar por todo esse histórico sem restrição. E porque o repositório é local, o desenvolvedor é seu dono e tem direito de escrita nele - diferente de servidores centralizados onde somente quem possui a famigerada “permissão de commit” pode escrever nele.
Justamente porque o repositório inteiro é clonado na máquina de cada desenvolvedor, mesmo que o tal “hub eleito” seja destruído, qualquer outro pode ser imediatamente eleito a hub e todos podem ser sincronizar de volta com ele.
No caso do Git, principalmente, ele foi criado com o objetivo de ter branches e merges triviais e imediatos. Essa é sua principal ferramenta. Com um sistema de mesclagem entre diferentes branches que realmente funciona de maneira trivial, o programador finalmente pode fazer tudo que quiser sem se preocupar: tem uma grande idéia que ainda não sabe se será realmente realizável? Crie um branch e desenvolva lá. Se funcionar, mescle com o tronco principal, senão jogue o branch fora, sem prejuízos.
Ainda mais: imagine que você está no meio de um desenvolvimento experimental, mas ao mesmo tempo foi detectado um bug urgente no tronco principal. Com o Git, trocar de branches também é trivial, você deixa seu desenvolvimento experimental no seu branch, volta ao branch principal, faz as correções, coloca em produção e pode voltar ao seu branch experimental e trazer as correções junto, tudo sem problema algum.
Git - Desenvolvimento Ágil Distribuído
O Git está disponível em praticamente todos os sistemas operacionais.
Para Windows baixe o instalador do msysGit.
Num Linux como Ubuntu, use um dos instaladores como apt-get, assim:
apt-get install git-core git-svn
E no Mac, com a ajuda do MacPorts, instale assim:
port install git-core +svn
Isso lhes dará acesso a uma centena de comandos Git. Apenas alguns deles são realmente importantes. A quantidade de comandos é porque o Git foi criado para ser uma infraestrutura de gerenciamento de conteúdo. Ele funciona praticamente como um file system de versionamento. Para os cientistas da computação recomendo ler sobre Directed acyclic graph, que é a estrutura que o Git utiliza para gerenciar o conteúdo. Diferente de outros VCS ele não versiona arquivos e diretórios, mas sim conteúdo. Ou seja, se dois arquivos com nomes diferentes tiverem o mesmo conteúdo, no Git eles serão apenas um único ‘blob’ de dados. É uma das chaves de sua eficiência.
Para criar um novo repositório Git, a partir do diretório do seu projeto (considere que este diretorio tem pelo menos um arquivo com conteúdo) faça assim:
cd meu_projeto
git init
git add .
git commit -a -m “commit inicial”
Isso criará um repositório no diretório .git, adicionará seus arquivos ao índice e fará o commit ao repositório que foi criado. Ao contrário do CVS e Subversion, o Git não polui todos os subdiretorios do seu projeto com diretorios .cvs ou .svn. O Git cria apenas um único .git na raíz do seu projeto. Aliás, se quiser eliminar o repositório, apenas apague o diretório .git.
O Git foi criado para ser ultra-eficiente no gerenciamento de branches. Imediatamente todo seu código está já em um branch, chamado ‘master’ por padrão. Para listar os branches use:
git branch
Agora, digamos que você quer experimentar algum código mas não quer se comprometer a já colocar no master. Nesse caso podemos criar um novo branch:
git checkout -b teste
Esse comando cria um novo branch chamado ‘teste’ e já o leva para esse branch. Git tem o recurso de inline branches, ou seja, você troca de branches no mesmo diretório. Nos exemplos a seguir o texto que está após # é apenas um comentário para facilitar a compreensão. Como acabamos de criar o branch ‘teste’, parta do princípio que ainda estamos nesse branch. Comece criando um arquivo texto com um conteúdo qualquer nesse diretório, vamos chamá-lo de readme.txt:
# editando arquivo readme.txt
git status # mostra o que foi adicionado, criado ou apagado desde o último commit
git add readme.txt # adiciona o novo arquivo ao índice
git commit -a -m “adicionando readme” # grava a modificação no branch atual, ‘teste’
git checkout master # muda de volta para o branch ‘master’
Neste ponto, olhe novamente para o diretório - use o comando ls ou, no Windows, dir - e verá que o arquivo readme.txt não está aqui!
Isso porque esse arquivo foi criado no branch ‘teste’. O último comando que demos volta ao branch ‘master’ e lá esse arquivo não existe. Para voltar ao branch ‘teste’ faça:
git checkout teste
E você pode continuar desenvolvendo nesse branch. Ao criar novos arquivos sempre use ‘git add’ para adicioná-los ao índice. Depois faça commit. No Linux e no Mac existe um aplicativo chamado Gitk que permite visualizar a árvore de histórico graficamente. Veja como nosso exemplo está neste ponto:
Ou seja, o branch teste é mais ‘recente’ do que o branch master, porque acabamos de adicionar o arquivo readme.txt nele.
Agora, vamos à uma situação corriqueira: digamos que você está no branch ‘teste’, mas seu chefe lhe avisa que na versão atual (que está no branch ‘master’) foi descoberto um bug e você precisa urgentemente corrigir e colocar em produção. Como fazer? Considerando que você ainda está no branch ‘teste’ faça:
git commit -a -m “fazendo commit das ultimas modificacoes no teste
git checkout master # voltando ao branch master
# corrigindo o bug, no caso crie um arquivo chamado fix.txt com qualquer conteudo
git add fix.txt # adicionando o novo arquivo no índice do master
git commit -a -m “gravando a correcao do bug” # gravando no master
# aqui você colocaria sua correção em produção, faça de conta
![]()
git checkout teste # voltando ao branch teste
Liste novamente os arquivos. Você verá que no branch teste não existe o arquivo fix.txt. Obviamente porque ele está no branch master. Vejamos graficamente como isso ficou:
Isso significa o seguinte: o branch teste ainda é baseado na versão antiga do master. Enquanto isso surgiu um novo commit com o tal ‘fix.txt’ que ficou acima do teste. E como você sincroniza seu branch teste com o master para ganhar as mesmas correções?
git rebase master
O comando rebase desfaz tudo que você fez no branch teste, todos os seus commits, daí ele aplica o commit de correção que você fez no branch master e então reaplica um commit de cada vez do que você tinha feito no branch teste. Dessa forma é como se você tivesse acabado de criar o branch teste a partir do master e tivesse codificado a partir dali.
Veja graficamente acima: é como se primeiro tivesse sido feita a correção do bug e depois o arquivo readme.txt tivesse sido criado.
Finalmente, digamos que nossa nova funcionalidade no branch teste funciona, estamos satisfeitos com ela e queremos colocar o que fizemos de volta ao branch master. Nesse caso fazemos o seguinte:
git checkout master # voltando ao master
git merge teste # mesclando as modificações do teste no master
Vejamos graficamente:
Excelente! Agora os branches master e teste estão sincronizados entre si. Como finalizamos a funcionalidade que queríamos, podemos apagar o branch teste, pois não queremos mais ele:
git branch -d teste
Repositório Remoto de Git
Apesar de sua natureza distribuída, digamos que queremos já eleger um nó para fazer o papel do “centralizador”. Note que isso não restringe as atividades dos desenvolvedores, apenas organiza o trabalho. Não confundir esse modo de trabalho com os modelos centralizados pois as diferenças são muitas, incluindo que dois desenvolvedores podem clonar o repositório central e desenvolver em um sub-grupo separado sem nunca devolver as mudanças a esse servidor, por exemplo.
Podemos rodar o Git com o servidor Web Gitorius, mas vamos manter tudo simples por enquanto e usar o suporte a SSH. Qualquer servidor Linux/Mac que tenha um servidor SSH de pé serve como repositório remoto de Git. A Locaweb, por acaso, tem esse suporte em todas as suas hospedagens Linux compartilhadas. Portanto sua conta aqui é potencialmente um bom ninho para Git.
Sugerimos que você e todos de sua equipe criem o par de chaves para SSH e adicionem a chave pública ao arquivo ~/.ssh/authorized_keys no servidor remoto. Se não souber como realizer isso, aguardem mais um artigo sobre o assunto ou leiam este outro. Isso permite que você acesse sua conta via SSH sem precisar digitar senhas o tempo todo. Somente a máquina que mantém a chave privada pode fazer isso, claro, por isso tome cuidado com essa chave.
Então, vamos fazer de conta que entramos em nossa conta, assim:
ssh meu_login@meu.dominio.ws
Dentro da sua conta, podemos criar um diretorio qualquer para servir como o repositório eleito para ser o ‘centralizador’, da seguinte forma (novamente # denota comentário)
mkdir -p repo/projeto.git
cd repo/projeto.git
git –bare init
Pronto, isso é tudo que precisamos fazer. Podemos digitar ‘exit’ para sair do servidor e retornar à nossa máquina local. E, de dentro do diretório do projeto que estávamos trabalhando acima, fazemos o seguinte:
git remote add origin ssh://meu_login@meu.dominio.ws/~/repo/projeto.git
git push origin master
Primeiro, adicionamos o repositório remoto com o nome de ‘origin’. Depois ‘empurramos’ (push) o que temos no nosso branch ‘master’ para o repositório ‘origin’.
Pronto. Agora vamos simular um segundo desenvolvedor entrando no jogo. Para isso, abra outro terminal e de outro diretório que não onde está o projeto acima, faça o seguinte:
git clone ssh://meu_login@meu.dominio.ws/~/repo/projeto.git
# edite o arquivo readme.txt e modifique seu conteúdo
git commit -a -m “modificando o readme”
git push
Nesse caso, nosso segundo desenvolvedor primeiro clonou o repositório remoto, modificou um arquivo, fez o commit no repositório local e depois empurrou as modificações ao servidor remoto.
Eu sei que isso está ficando confuso, mas mantenha o foco! Agora, vamos retornar ao diretório original onde começamos este exercício. De lá, podemos “puxar” (pull) as modificações que estão no servidor, assim:
git pull origin
Vejamos graficamente:
Veja que recebemos o commit “modificando readme” que o segundo desenvolvedor havia feito. E assim está criado um pequeno fluxo de trabalho - bastante simples - entre dois desenvolvedores e um servidor central, totalizando 3 nós. Note que o primeiro desenvolvedor pode fazer “git remote add” de um diretório local, não precisa ser um servidor SSH! Ou seja, se o segundo desenvolvedor colocar seu repositório num pen drive, dar ao primeiro desenvolvedor e este der git remote add apontando para o diretório no pen drive, ele já pode dar git pull dele !! E isso pode se extender de diversas formas.
Mais importante do que isso, com os recursos de branch, rebase, merge, o desenvolvedor ganha ferramentas poderosas para liberar sua criatividade e inovação, criando coisas sem prejudicar o tronco principal de desenvolvimento.
Mais a Aprender
Este micro-exemplo mal toca a ponta do iceberg do que o Git pode fazer. Para o próximo artigo pense neste cenário:
- Você gosta de um projeto open source qualquer, digamos, Wordpress, que tem o código-fonte liberado na internet
- Esse repositório está em Subversion, e não em Git
- Quero clonar esse repositório, pois eu quero customizar seu código para servir a minhas necessidades particulares.
- Quando o código do Wordpress sofre atualizações no repositório Subversion original, quero ser capaz de trivialmente puxar essas atualizações e automaticamente mesclar com minhas customizações sem precisar de quase nenhum trabalho!
Esse cenário é muito interessante pois abre toda uma gama de soluções para equipes que querem ser flexíveis.
Para saber mais recomendo continuar daqui as seguintes leituras:
- Jogar Pedra em Gato Morto: por que Subversion não presta
- Git para Cientistas da Computação
- Micro Tutorial de Git
- Aprenda GIT pelo PeepCode
- Git Community Book - coletânea com muito material explicando o Git
- GitCasts - video podcasts explicando as diversas funcionalidades do Git, passo-a-passo
- GitHub - o maior repositório público de projetos em Git que inclui, por exemplo, o próprio Ruby on Rails
Antes que perguntem: “Será que Git vai suplantar o Subversion, como ele um dia já fez com CVS?” Boa pergunta, eu particularmente acredito que não e mais do que isso: acredito que não é necessário. Highlander só existe no cinema: a filosofia do “só pode haver um” não só é antiquada como é prejudicial àqueles que pensam assim - não para mim, felizmente. Existem tecnologias que são adotadas em massa devido ao massivo trabalho de marketing, assim como na indústria de música que fabrica cantores e Top Hits. Pense em Git como uma banda Indie
Novamente, leia o livro The Long Tail para entender a economia da abundância e da escolha, contrária à antiga mentalidade do limitante e “Top 10″. No fundo a diferença é que muitos programadores (que eu chamo de “meros codificadores”) não tem nem a vontade nem a habilidade para aprender coisas novas, ou como diz o ditado: “Cachorro velho não aprende truque novo”.
Tecnologias e paradigmas inovadoras como DVCS existem e estão em crescimento na Cauda Longa dentro de equipes e empresas que pensam à frente: onde qualidade, produtividade, flexibilidade, time to market e trabalho gratificante são valores considerados mais importantes do cargos e burocracia.
E para você, desenvolvedor que é obrigado a usar Subversion e não vê perspectiva de sua empresa/cliente mudar de idéia, uma dica (que vou elaborar em outro artigo, mas se tiver pressa leia este): git-svn. Esta ferramenta permite não somente clonar um repositório Subversion em seu próprio repositório Git local, como também permite enviar seus commits locais de Git de volta ao servidor como commits de Subversion! Ou seja, você pode desenvolver usando Git sem sua empresa sequer se dar conta disso!
Bom divertimento!
Tags: dvcs, git, produtividade, repositorio, subversion, svn



5 de setembro de 2008 às 22:25
Excelente artigo, parabéns!
6 de setembro de 2008 às 8:31
Parabéns Akitão! Muito completo e esclarecedor.
5 de dezembro de 2008 às 17:19
Akita, parabéns pelo artigo!
Eu estava seguindo as suas instruções para criar um repositório remoto na minha conta da Locaweb e notei que o comando correto é “git –bare init” (traço traço bare) ao invés de “git –bare init” (traço bare) como aparece no tutorial.
Muito legal poder ter um repositório git na minha conta :))