Páginas

Saturday, February 28, 2009

Brincando com o Bazaar (bzr)

Nesse carnaval tirei um tempo para ver como funciona o Bazaar.

Mas o que é isso? Bem, o Bazaar é um DVCS - Distributed Version Control System -, um software que, simplificadamente, serve para guardar diversas versões de arquivos. Em geral, esses "arquivos" estão relacionados a código-fonte, mas podem ser qualquer coisa, como imagens, pdfs, executáveis, etc.

Um sistema de versionamento famoso é o Subversion (svn), que é um sucessor do CVS. Entretanto, o Bazaar, assim como outros DCVSs, são essencialmente diferentes desses dois.

O SVN e o CVS são sistemas centralizados, com pouco suporte para operações offline, e possibilidades (facilidade) de colaboração limitadas. As operações de controle de versão ocorrem num repositório central, necessitando conexão de rede/Internet.

Já os sistemas distribuídos, possuem diversos repositórios; repositórios locais, onde o desenvolvedor pode salvar (commit) seu trabalho, e repositórios remotos onde ocorre a integração (merge) das partes.

Bem, a minha intenção aqui não é explicar como funciona o SVN nem o CVS, nem dar detalhes do que eles são. O trecho acima foi só para tentar nivelar os desentendidos :)

Mais informações nos links que apontam para a Wikipedia!


Voltando ao Bazaar, existem outros "concorrentes" por aí, boas opções também. Dentre as principais: Mercurial e Git.
Tenho usado o Git no meu estágio, e achei ele um pouco "fora do meu estilo". Também tem um ponto chato que é rodá-lo no Windows -- um grande problema. E como meu dia a dia é Linux pra cá, Windows acolá, então é uma limitação relevante pra mim.

Meu orientador Carlo me deu uma amostra grátis do Bazaar algumas semanas atrás, lá no NCE/UFRJ, e achei por bem tirar um tempo pra brincar com ele por minha conta. E foi o que fiz em algum momento do feriadão de carnaval. Instalei o Bazaar no Ubuntu e passei a usá-lo em um projeto pessoal.

A instalação foi muito fácil. Nos repositórios padrão do Ubuntu 8.10, a versão do Bazaar não era a mais recente, portanto, adicionei ao meu sources.list o repositório do Bazaar no Lauchpad.

Conforme diz aqui bastou eu abrir o gerenciador de pacotes e pedir para adicionar essas duas linhas:

deb http://ppa.launchpad.net/bzr/ppa/ubuntu intrepid main
deb-src http://ppa.launchpad.net/bzr/ppa/ubuntu intrepid main
Depois de atualizar a lista de pacotes disponíveis, lá estava o Bazaar 1.12, assim como o pacote bzr-gtk que traz uma interface gráfica pro mesmo.

Agora enquanto escrevo, vou instalar no Windows...
Extremamente fácil: só baixar e executar. Instalado e funcionando muito bem.
Desta forma, instalei o Bzr standalone, isso é, não está instalado junto ao meu Python do sistema.

Pois é, o Bazaar é escrito em Python, é muito fácil de usar, e é uma mão na roda para por exemplo manter o pendrive, notebook, e outros pcs sincronizados. E de quebra um local faz backup do outro...

A idéia do Bazaar é de ser um software fácil de usar, e com pouco tempo de uso já me sinto confortável para fazer diversas tarefas. Sua documentação é boa, funciona em qualquer lugar que rodar Python, o que significa umm... qualquer lugar...

Também é muito legal usar o bazaar interfaceando com outros sistemas de controle de versão. O Bazaar, até onde sei, é o único que pode ser usado com o SVN, Git, Mercurial, tudo ao mesmo tempo. Existem plugins que integram o bzr com cada um destes outros projetos, de forma que pela linha de comando do bzr posso fazer checkout e commits em repositórios svn... ou git...

Por fim, li uma dica muito bacana sobre como colaborar em projetos usando o bzr. O projeto pode estar usando qualquer controle de versão, ou mesmo usando nenhum :)

A idéia é a seguinte:
    # criar um diretório para guardar seu trabalho
mkdir projeto
cd projeto
# Criar um repositório do bzr (para otimizar o uso de espaço em disco)
bzr init-repo --trees .
# Pegue o codigo oficial do projeto
svn co http://url/do/repositorio/oficial/do/projeto original

Então agora temos um diretório contendo o código original do projeto. A idéia é deixar o diretório "original" intocado, sendo este apenas uma referência.

Agora vamos criar alguns branches no Bazaar para organizar o trabalho:
    # Criando um branch do bzr para o codigo original
cd original
bzr init
bzr add .
bzr ci -m'Importação do projeto'
# Criando um branch principal
cd ../
bzr branch original main

No branch main, podemos fazer as modificações necessárias para fazer o projeto rodar no nosso sistema, se for necessário. Essas modificações não serão enviadas de volta ao repositório original.

    cd main
# Faça as alterações locais e prossiga
bzr ci -m'Adicionando mudanças locais'

Agora, sempre que for trabalhar em um patch/funcionalidade, crie um novo branch para ela. Isso faz com que as mudanças no projeto original sejam independentes.

    # Criando um branch para trabalho em uma funcionalidade
cd ..
bzr branch main algumafuncionalidade
cd
algumafuncionalidade
# Implemente a fucionalidade e então
bzr ci -m'Adicionada funcionalidade xyz'

Agora, certifique-se que o código está atualizado em relação ao original para que seu patch seja limpo (atualize frequentemene para evitar uma grande quantidade de conflitos a serem resolvidos).

    cd ../original
svn update

Isso trará as mudanças do repositório SVN oficial do projeto (pode ser outro comando, de acordo com o controle de versão usado no projeto...). Não deve haver nenhum conflito nesse momento, já que nada foi feito localmente em 'original'. Note que podem haver novos arquivos (linhas com um A na saída do svn update). O comando bzr unknowns pode te ajudar agora. Se houver algum arquivo novo, adicione-o ao bzr:

    bzr add arquivonovo
# ou bzr add $(bzr unknowns)
bzr ci -m'Mesclando com original do svn revisão 1234'

Isso significa que seu branch original está atualizado no bzr. Agora é hora de propagar as novidades para os branches com cada nova funcionalidade. Mas antes vá ao branch main para manter suas alterações de funcionamento local.

    cd ../main
# Mesclar com as alterações em original
bzr merge
# Se houver algum conflito, solucione e então
bzr resolve file
# Quando tudo estiver ok (bzr status e bzr diff podem
# ajudar nessa hora)
bzr ci -m'Mesclando com original do svn revisão 1234'

E agora o mesmo para os branches de cada funcionalidade.

    cd ../algumafuncionalidade
bzr merge
# 'bzr resolve' se necessário
bzr ci -m'
Mesclando com original do svn revisão 1234'

Pode parecer muito trabalho (é mais simples que o Git :P), mas isso é feito bem rápido, especialmente se o desenvolvimento for feito "um passo de cada vez". Entretanto, os benefícios dessa forma de trabalhar superam essa trabalheira.

Como comparado ao svn o bzr é superior na hora de fazer merge, trabalhando desta forma reduzirá a quantidade de trabalho manual necessária para resolver conflitos.

Agora que você tem um nova funcionalidade implementada em um branch, você pode enviá-la para o repositório oficial do projeto!

É muito fácil. Já que separamos as funcionalidades em branches, os diffs sempre serão limpos, e para criá-los:

      bzr diff -r branch:../main > ../funcionalidade.diff

Agora você pode revisar o diff e enviar para os mantenedores do projeto como um patch.

Você pode deixar seu branch de lado, e criar novos branches se quiser trabalhar mais. Se os mantenedores pedirem alguma alteração no seu patch para a funcionalidade que enviou, basta voltar ao branch e fazer as alterações, e enviar um novo diff.

Se o patch for aceito, então suas alterações irão parar na próxima atualização do código no repositório svn, e irão se propagar para todos os seus branches bzr. Não haverá nenhum conflito.

Se o patch não for aceito, mas mesmo assim você qe manter suas alterações localmente, é também fácil. Simplesmente faça um merge do seu branch com o main branch, que então vai propagar para os outros branches de funcionalidade.
    cd ../main
bzr merge ../algumafuncionalidade
bzr ci -m'Adicionando funcionalidade'

Agora, quando você atualizar os outros branches de funcionalidade, eles vão receber a funcionalidade, sem que seus diffs a contenham, mantendo os patches separados.

Se quiser implementar um funcionalidade em várias etapas, você pode criar branches de funcionalidade que dependam um do outro.
     bzr branch main pequena.mudanca
bzr branch
pequena.mudanca grande.mudanca

Agora, as mudanças de pequena.mudanca se propagam para grande.mudanca, e você pode gerar três patches:

   # Diff para implementar pequena.mudanca
cd pequena.mudanca
bzr diff -r branch:../main
# Diff para implementar grande.mudanca
cd grande.mudanca
bzr diff -r branch:../main
# Criar diff para implementar grande.mudancao que é dependente de
# pequena.mudanca. Útil se a segunda parte da mudança ainda precisar
# ser discutida, ou se for aceita em etapas.
cd grande.mudanca
bzr diff -r branch:../pequena.mudanca

Portanto, fica aqui uma amostra de como o bzr pode trazer flexibilidade para trabalhar em um projeto, não importa qual controle de versão que seja usado oficialmente.


E eu, super feliz com o bzr :)

8 comments:

Unknown said...

Eu lembro que na PyConBrasil 2008 falaram que o Bazaar era muito mais lento que o Mercury. O teste foi importar/converter o repositório do Python, eu acho. Com o Bazaar, demorou muito mais tempo, e ele gastou bem mais espaço em disco.

Se depois você puder comparar os dois (Bazaar e Mercury), será ótimo!

Rodolfo said...

De alguma forma eu não gostei do Mercurial... acho que os nomes dos comandos parecem mais estranhos, não sei... alguma coisa parece errada.

No site do Bazaar eles se defendem dizendo que esse papo de ser lento é coisa do passado. Para as pequenas coisas que fiz, ele foi super rápido e responsivo.

Sua proposta é boa, vou tentar fazer essa comparação no fim de semana.

Cliff Oliveira said...

estou com dificuldades para usar o bazaar em rede. Temos quatro máquinas e até o checkout funciona mas na hora do pull para atualizar ele diz que não há atualizações a fazer, mas tem vários commites feitos.
como devo proceder para resolver isso ?

Rodolfo said...

Cliff, imagino que você está usando alguma forma de repositório central de onde fez checkout. Se não tem nada para atualizar com um pull possivelmente deve ser porque não fez push nas máquinas onde desenvolveu e fez commit. Note que nos gerenciadores distribuídos os commits são locais, e para enviá-los pela rede precisa fazer push.
Basta um "bzr push [endereço]" nas máquinas com commit, e depois vai poder fazer pull. Atente também ao fato que você deve precisar fazer alguns merges pelo caminho...

Cliff Oliveira said...

beleza, vou tentar novamente hoje,
fazendo da forma que vc falou
meu principal objetivo é manter uma copia master para os quatro micros da rede

Cliff Oliveira said...

saudações,
volto a pedir ajuda, parece que andei um pouco mas mesmo assim, não consigo atualizar a copia original.
quando faço as mudanças numa máquina que tento enviar ele me retorna:

This transport does not update the working tree of: ftp://cliff@192.168.1.3/meubazar2/. See 'bzr help working-trees' for more information.
FTP temporary error: 451 /meubazar2/.bzr/repository/upload/zs00wfzubgs0wt4jd1cb.fetch: Append/Restart not permitted, try again. Retrying.
FTP temporary error: 451 /meubazar2/.bzr/repository/upload/zs00wfzubgs0wt4jd1cb.fetch: Append/Restart not permitted, try again. Retrying.
FTP temporary error: 451 /meubazar2/.bzr/repository/upload/zs00wfzubgs0wt4jd1cb.fetch: Append/Restart not permitted, try again. Retrying.
bzr: ERROR: Transport error: FTP temporary error during APPEND /meubazar2/.bzr/repository/upload/zs00wfzubgs0wt4jd1cb.fetch.Aborting. 451 /meubazar2/.bzr/repository/upload/zs00wfzubgs0wt4jd1cb.fetch: Append/Restart not permitted, try again

já tentei usando o help, mas não obtive sucesso
:(
imagina o que pode ser isso ?

Rodolfo said...

Cliff, não sei exatamente o que é, mas pelo que falou antes você fez um "checkout". O ciclo mais normal é criar seu repositorio (bzr init), depois adicionar arquivos e commitar (bzr add, bzr commit), e fazer push para o repositorio central (bzr push). Para começar a trabalhar de outra maquina, ao inves de checkout voce faz um branch (bzr branch).
Na documentacao do bazaar tem a descricao de como usa-lo no formato centralizado, e voce tambem pode consultar os detalhes de cada comando e ver a diferença entre fazer checkout e branch.

Cliff Oliveira said...

até essa parte esta funcionando bem, crio o original e consigo normalmente compartilha-lo com outras máquinas.
meu problema se dá quando uma das máquinas que trabalha com essa copia, tenta enviar as modificações.
O bzr merge diz que não há nada a fazer
o pull tbm não funciona
:(