SVN Guia rápido

Como grande apreciador e usuário há anos do SVN, não poderia deixar de dedicar um pequeno artigo sobre esta fantástica ferramenta de controle de versão, principalmente pela escassez de materais na Internet discutindo seus conceitos de forma pragmática.

Assim, resolvi aproveitar alguns materiais que eu havia escrito para utilização pelos times de desenvolvimento nos quais atuo, incrementei alguma coisinha aqui e acolá e preparei este estrambolicamente dupper master quase infinito artigo.

Para facilitar a leitura, o artigo está dividido em 7 partes:

Público alvo: comentários sobre a quem se destina a leitura deste artigo;
Controle de versão e SVN: o que é controle de versão e como o SVN se encaixa nesse paradigma;
Termos e conceitos básicos: conceitos básicos para entendimento do funcionamento e organização do SVN;
Boas práticas: breve manual de boas práticas na utilização do SVN;
Dicas de utilização: dicas diversas de utilização do SVN;
Ferramentas de apoio: algumas ferramentas interessantes para tornar o uso do SVN mais prático.
Ao infinito e além: costumeira lista de links interessantes.

Público alvo

O cerne deste artigo não é a discussão da utilização do SVN a partir de comandos ou questões técnicas da ferramenta. Para tal, há documentações, livros e artigos na rede muito completos sobre o tema. O público alvo deste artigo são utilizadores do SVN que já tenham familiaridade com suas idiossincrasias e que desejam um melhor entendimento do modelo organizacional da ferramenta e de como estruturar um processo em torno do SVN para tornar mais eficaz o gerenciamento do código-fonte de suas aplicações.
Controle de versão e SVN

Controle de versão é a arte de gerenciar mudanças em informações. Para programadores, é um paradigma obrigatório a ser seguido para assegurar a saúde do código-fonte, ainda mais em grandes equipes atuando cada qual em partes distintas de um projeto.
Back to the FutureVocê, desenvolvedor, também precisa de uma
máquina do tempo para seu código.

O Subversion, ou simplesmente SVN, é uma ferramenta de controle de versão muito poderosa que permite, além do desenvolvimento colaborativo a partir de um repositório único, merge de conteúdo, armazenamento de logs e geração de estatísticas diversas.

Atuando como a máquina do tempo do desenvolvedor, ferramentas com o SVN permitem retornar o código a um estado anterior, facilitando a análise implementações realizadas e a mesclagem de implementações distintas de períodos diferentes para a criação de uma única versão.

(Embora eu seja fãzaço e ávido partidário do SVN, tenho flertado nos últimos tempos com os ótimos Mercurial e GIT, os quais têm realmente me surpreendido e me feito repensar o uso do meu amado idolatrado salve salve SVN. Todavia, isso fica para outro artigo…)
Termos e conceitos básicos
TortoiseSVN Menu

Repositório
É o local aonde estão contidos todos os arquivos do projeto. É armazenado no banco de dados do SVN.
Working Copy
Literalmente, uma cópia de trabalho local na qual o desenvolvedor atua. É criada sempre que é feito checkout de algum projeto.
Checkout
Ato de fazer download de um projeto para a máquina local, de modo que seus arquivos estejam vinculados ao SVN e passíveis de manipulação. O projeto para o qual será feito o checkout deve existir no repositório.
Import
Ato de envio dos arquivos de um novo projeto para o repositório. Após o import, obrigatoriamente um checkout deve ser realizado para que a working copy seja vinculada ao SVN.
Export
Ato de obtenção de um projeto do repositório sem vinculação ao SVN.
Commit
Ato de envio das modificações realizadas localmente para o servidor SVN.
Update
Ato de obtenção das atualizações presentes do servidor SVN, atualizando a cópia local
Revision
Número que identifica cada uma das alterações ou conjunto de alterações realizadas em um repositório. Tal número é obtido a partir de uma sequência a qual é compartilhada por todos os diretórios do repositório.
HEAD
É a revisão mais recente do repositório
Diretórios especiais
Existem no SVN três diretórios especiais com funções bem definidas:

trunk: armazena a versão funcional mais recente de desenvolvimento.
branches: armazena versões de desenvolvimento paralelo oriundas do trunk, porém isoladas deste. Deve ser utilizado quando uma implementação trazer o risco de afetar a integridade do trunk.
tags: armazena etiquetas para facilitar a localização de revisões. Cada etiqueta possui um nome único que a identifica, sendo criada como um diretório, sempre através do trunk.

Branch/Tag
Refere-se à geração de branches ou tags a partir de um trunk ou geração de um branch a partir de uma tag ou outro branch.
Merge
Refere-se à mesclagem de revisões entre os diretórios especiais. Sempre deve ser realizada com a working copy apontando para o destino do merge.
Switch
Alteração do repositório utilizado por uma working copy. É realizada uma atualização ou mesclagem dos arquivos para assegurar que a working copy contenha exatamente o conteúdo do novo repositório mais quaisquer alterações locais.
Relocate
Realocação do endereço de um repositório. Apenas atualiza o endereço, sem realizar nenhum tipo de atualização nos arquivos.

Boas práticas

Toda revisão deve ser comentada para facilitar o entendimento das alterações realizadas.
O código no trunk deve sempre estar pronto para ser compilado e colocado em produção se necessário. Nesse sentido, uma ferramenta de Integração Contínua, como o CruiseControl, deve ser utilizada para a geração de builds de teste a cada commit e todas as noites ao longo da semana.
É dever de cada programador assegurar que seus commits não causem a quebra do build. Novamente uma ferramenta de Integração Contínua pode auxiliar nesta tarefa.
As alterações em um código-fonte devem ser submetidas ao repositório o mais rápido possível. Para tal, é recomendável a divisão das implementações em pequenos pacotes compiláveis e funcionais ou, ao menos, que não causem a quebra do build. Quanto mais tempo um arquivo mantém-se na máquina de um desenvolvedor em edição, mais difícil será sua mesclagem e maior será o risco de quebra de build.
Toda a quebra de build deve ser tratada com máxima prioridade no sentido de sua correção. Mais uma vez uma ferramenta de Integração Contínua pode auxiliar nesta tarefa.
Caso um build esteja quebrado, não se deve submeter alterações ao repositório até que o build seja novamente compilável. Isso assegura que todos os que realizarem updates terão sempre uma versão compilável e funcional oriunda do repositório.
O projeto no repositório deve conter quaisquer componentes e ferramentas necessárias para o funcionamento da aplicação na máquina do desenvolvedor.
Evitar o envio de alterações próximo do fim do expediente. Caso haja algum problema com o commit realizado, poderá não haver tempo para corrigi-lo naquele dia e o build poderá ficar quebrado por um longo período.
Todo e qualquer backup de versões deve ser mantido no repositório, preferencialmente como uma tag.

Dicas de utilização
Uso do trunk

O trunk sempre representa a última versão de desenvolvimento disponível. Nesse sentido, é aqui que ocorre a integração do projeto a partir de builds automatizados e é aqui que a versão funcional mais recente deve estar presente.

É do trunk também que os branches e tags devem ser gerados (embora branches possam ser gerados de tags e outros branches sem restrições técnicas). A ferramenta de revisão gráfica do TortoiseSVN (Revision Graph) permite visualizar os relacionamentos entre as pastas especiais a partir de diagramas.
Fluxo básico de atividades

O fluxo básico de atividades no repositório consiste na utilização do trunk como ponto principal de checkout para o desenvolvimento. Entretanto, quaisquer tarefas que possam causar grande impacto no trunk devem ser realizadas em um branch separado, o qual receberá as alterações do trunk ao longo do dia ou ao fim do dia para que este seja mantido atualizado.

Tags são utilizadas como backups e marcação de releases diversos do projeto.

Segue abaixo explanação da utilização do fluxo:
Diagrama do fluxo

Geração de backup da versão do trunk para marcação de um ponto de restauro rápido antes do início dos branches a partir da opção Branch/Tag (opcional);
Criação de branch para realização de nova implementação que pode impactar no trunk a partir da opção Branch/Tag;
Integração de alterações realizadas no trunk ao branch a partir da ferramenta de mesclagem Merge a Range of Revisions;
Criação de nova branch para realização de nova implementação que pode impactar no trunk a partir da opção Branch/Tag;
Conclusão do primeiro branch criado, ocorrendo a reintegração deste no trunk a partir da ferramenta de mesclagem Reintegrate a Branch e sua deleção;
Atualização da segunda branch criada com as atualizações recém realizadas no trunk a partir da ferramenta de mesclagem Merge a Range of Revisions;
Conclusão da segunda branch criada, ocorrendo a reintegração desta no trunk a partir da ferramenta de mesclagem Reintegrate a Branch e sua deleção;
Geração de etiqueta de release da versão do trunk a partir da opção Branch/Tag.

Fluxo básico de atuação em projeto fechado

Quando em atuação em projetos fechados de customização a um cliente, tem-se comumente uma única versão da aplicação em produção, além de outras em ambientes diversos, como por exemplo homologação e testes.

Neste caso, o fluxo básico de atividades também é utilizado. Entretanto, a cada release gerado, além da tag é criado um branch que representa a versão criada. Assim, tem-se no trunk a última versão de desenvolvimento e, em branches separados, cada uma das versões implantadas em ambientes diversos.

Dessa forma, pode-se prestar manutenção às versões presentes em cada um dos ambientes da aplicação de forma simples. Toda vez que uma nova versão de um determinado ambiente é gerado, o branch anterior para tal ambiente é excluído.

Neste fluxo, sempre se espera que todas as revisões do trunk anteriores ao release façam parte deste, não havendo seleção de revisões na concepção de releases.

Segue abaixo explanação da utilização do fluxo:
Diagrama do fluxo

Geração de backup da versão do trunk para marcação de um ponto de restauro rápido antes do início dos branches a partir da opção Branch/Tag/ (opcional);
Criação de branch para realização de nova implementação que pode impactar no trunk a partir da opção Branch/Tag;
Integração de alterações realizadas no trunk ao branch a partir da ferramenta de mesclagem Merge a Range of Revisions;
Conclusão do primeiro branch criada, ocorrendo a reintegração deste no trunk a partir da ferramenta de mesclagem Reintegrate a Branch e sua deleção;
Geração de etiqueta de release da versão do trunk a partir da opção Branch/Tag;
Criação de branch para o release recém gerado a partir da opção Branch/Tag;
Mesclagem das alterações realizadas no branch do release ao trunk a partir da ferramenta de mesclagem Reintegrate a Branch. Tal branch se manterá ativo enquanto a versão que o representa estiver em utilização.

Fluxo de atuação em projeto fechado com mesclagem de revisões

A exemplo do Fluxo básico de atuação em projeto fechado, neste fluxo também se considera que há apenas uma única versão da aplicação em produção, além de outras em ambientes diversos, como por exemplo homologação e testes.

Nesta técnica, o fluxo básico de atividades também é utilizado. Entretanto, a cada release gerado, é criado primeiramente um branch baseado em uma tag anterior de ambiente, no qual ocorre mesclagem de revisões do trunk, para que somente após o commit de tal branch seja criada uma nova tag de release que aponte para tal branch (o qual, por sua vez, aponta para o trunk).

Assim, tem-se no trunk a última versão de desenvolvimento e, em branches separados, cada uma das versões implantadas em ambientes diversos, sendo que tais versões, embora venham do trunk, são geradas sempre a partir de tags de versões ante
rios, mantendo dessa forma a seleção de revisões realizada.

Dessa forma, pode-se prestar manutenção às versões presentes em cada um dos ambientes da aplicação de forma simples, além da geração de releases baseados em determinadas revisões do trunk.

Toda vez que uma nova versão de um determinado ambiente é gerado, o branch anterior para tal ambiente é excluído.

Segue abaixo explanação da utilização do fluxo:
Diagrama do fluxo

Considerando-se importação inicial do repositório, deve-se inicialmente criar-se uma tag de release para algum dos ambientes, a qual servirá de base para geração do branch do ambiente com o qual a tag se relaciona a partir da opção Branch/Tag;
Criação de branch para a tag do release recém criado a partir da opção Branch/Tag. Tal branch se mantém ativo enquanto a versão que o representa estiver em utilização.
Criação de feature branch para realização de nova implementação que pode impactar no trunk a partir da opção Branch/Tag. O uso desse tipo de branch deve ser avaliado com cautela. O trunk deve sempre ser a versão mais recente de desenvolvimento;
Integração de alterações realizadas no trunk ao feature branch a partir da ferramenta de mesclagem Merge a Range of Revisions;
Conclusão do feature branch criado, ocorrendo a reintegração deste no trunk a partir da ferramenta de mesclagem Reintegrate a Branch e sua deleção;
Reintegração de correções de bugs realizadas no branch do release atual de algum dos ambientes ao trunk a partir da ferramenta de mesclagem Reintegrate a Branch;
Exclusão do branch de algum dos ambientes por conta de nova versão a ser criada para tal ambiente;
Criação de nova branch para o ambiente a ter a nova versão disponibilizada a partir da tag do último release do ambiente desejado utilizando-se da opção Branch/Tag;
Mesclagem de revisões do trunk na nova branch de release a partir da ferramenta de mesclagem Merge a Range of Revisions e posterior commit destas alterações na própria branch;
Geração de etiqueta de release da versão criada a partir do novo branch utilizando-se da opção Branch/Tag;
Mesclagem das alterações realizadas no branch do release ao trunk a partir da ferramenta de mesclagem Reintegrate a Branch. Tal branch se manterá ativo enquanto a versão que o representa estiver em utilização.

Fluxo de atuação em projeto fechado com múltiplos branches

Tal fluxo é uma derivação do Fluxo básico de atuação em projeto fechado. Diferente daquele, neste todas as alterações sempre são realizadas em branches que posteriormente são reintegrados ao trunk. Quaisquer versões a serem geradas (produção, homologação, teste, etc.) são criadas a partir de merge de revisões a partir do trunk sobre o próprio trunk ou de branches sobre o trunk, com posterior geração de novas branches e tag para tal versão.

Neste fluxo, o trunk é utilizado como a versão mais completa da aplicação, contendo todas as implementações já realizadas em branches separados.

O uso dos branches se dá para facilitar a divisão de tarefas e organização das alterações, de modo que solicitações descartadas sejam facilmente ignoradas e não reintegradas ao trunk.

Segue abaixo explanação da utilização do fluxo:
Diagrama do fluxo

Geração de backup da versão do trunk para marcação de um ponto de restauro rápido antes do início dos branches a partir da opção Branch/Tag (opcional);
Criação de branches para realização de novas implementaões a partir da opção Branch/Tag. Como o trunk possui todas as implementações já realizadas, tais branches devem ser criados com base em revisões específicas do trunk que contenham apenas as implementações desejadas;
Integração de alterações realizadas no trunk aos branches a partir da ferramenta de mesclagem Merge a Range of Revisions (opcional – diferente dos fluxos anteriores, a obtenção das últimas alterações pode não ser necessária, uma vez que um branch pode referir-se a uma revisão específica e não necessariamente à última versão presente no trunk);
Conclusão dos branches criados, ocorrendo a reintegração destes no trunk a partir da ferramenta de mesclagem Reintegrate a Branch e posterior deleção;
Geração de release a partir do trunk. Neste fluxo, a geração de release ocorre mesclando-se revisões do trunk em uma working copy de uma revisão específica (não necessariamente a mais recente) do próprio trunk ou dos branches. Assim, pode-se escolher exatamente quais revisões entrarão em uma release, assegurando pleno gerenciamento da montagem de uma versão. A criação do branch é feita a partir da opção Branch/Tag;
Geração de etiqueta de release a partir do branch recém gerado através da opção Branch/Tag;
Mesclagem das alterações realizadas no branch do release ao trunk a partir da ferramenta de mesclagem Reintegrate a Branch. Tal branch sempre estará disponível, não sendo excluído do repositório.