Fluxo e versionamento semântico com Git

Imagem para Fluxo e versionamento semântico com Git

GitPostado em  5 min de leitura

Hoje vou falar sobre algo bem interessante, que deixa o versionamento do nosso código bem organizado. Estão em dia com os assuntos Semantic Version e Git flow? Aposto que já utilizou essas regras, mas não tinha um conhecimento mais profundo sobre o assunto, ou já sempre utilizou seguindo à risca.

Já conheço e sigo o Git flow, a um bom tempo. Inclusive um dos meus projetos no github é sobre a documentação do mesmo. Não reinventei a roda, é mais para ter um registro de fácil acesso, para futuras explicações ou consultas.

Sobre Semantic Version, o site oficial que está na versão 2.0.0, explica com detalhes as regras.

Estudando os conteúdos acima, basta ter uma disciplina inicial para os processos e regras.

Tomada de decisões

Muitas perguntas podem surgir na cabeça com algumas situações. Vou ilustrar algumas.

  1. Digamos que estamos na versão 2.2.0 na branch master. Estamos planejando um novo recurso (feature), então a próxima versão deve se tornar 2.3.0. Em seguida, o cliente relata um bug crítico, forçando-nos a preparar um hotfix. Nós corrigimos o bug e colidimos a versão para 2.2.1. Mas, dados os 'insights' obtidos com a correção do bug, agora percebemos que talvez precisamos quebrar a API pública para que a feature funcione da maneira que queremos. E se fizermos isso, não devemos mais colidir com a versão 2.3.0. Em vez disso, devemos mover para a versão 3.0.0.

Regra: A alteração de versão ocorre quando nós nos ramificamos do desenvolvimento para o release, ou quando nos ramificamos do master para a branch de hotfix.

  1. Convenção de nomenclatura na branch de dev. Uma vez que todas as mudanças nas outras branchs devem ser mescladas de volta para dev, acho que a nomeação deve refletir que dev é praticamente sempre a versão mais recente do produto. Por isso, é interessante usar a convenção a.b.c-wip.d, onde wip (work-in-progress) significa trabalho em andamento e d é o número da compilação (build).

Regra: Sempre certifique-se de que o número de versão na branch de dev está em sincronia com o número mais recente em qualquer branch de hotfix ou release.

Exemplo:

A branch de dev estava em 1.2.0-wip.123 quando criamos a branch hotfix (hotfix/1.2.1). Seguindo a última regra, quando nós juntamos de volta a branch de dev, ele é será 1.2.1-wip.x.

Esta regra pode ficar complicada quando estamos trabalhando em um hotfix e uma branch de release simultaneamente. Na maioria dos casos, o número de versão da branch de release deve superar a de hotfix. Especialmente porque provavelmente queremos mesclar alterações da hotfix de volta para a branch de release antes de envolvê-lo.

  1. Convenções de nomenclatura nas branches de release. Eu não espero que os releases permaneçam nesta branch por muito tempo, então o ciclo de vida completo de alpha/beta/rc1/rc2 parece um exagero. No final, podemos usar o rc-prefixo, o que leva à seguinte notação: a.b.c-rc.d. Novamente, d é o número de compilação (build).

Vamos continuar com o exemplo. Nós decidimos quebrar a API, então criamos uma nova branch de release (release/2.0.0). A primeira marca nesta branch deve então ser 2.0.0-rc.x, onde x é o número de compilação. Mas o que deveria ser x neste caso? Isso traz a questão sobre quando o contador deve ser redefinido, se alguma vez.

Vamos examinar uma alternativa:

Alternativa: Redefinir o contador de compilação sempre que o número de versão for colidido

Juntamente com o número de versão, isso garante exclusividade. Também parece muito mais agradável, já que o número de compilação raramente atingirá além de três dígitos.

No entanto, ele introduz um outro problema: lembrar de redefinir o contador sempre que você alterar o número da versão. Ou, se vamos para a automação completa, como detectar quando o número da versão mudou.

Regra: Assegure-se de que cada tag de controle de versão seja exclusivo no repositório.

Exemplo passo a passo

Atividade do projeto Tag
O projeto começa, o master está vazio e estamos fazendo o commit do nosso primeiro recurso no desenvolvimento 0.0.0-wip.1
É feito o commit da tarefa A na branch develop de uma branch feature 0.0.0-wip.2
Correção rápida de erros diretamente no desenvolvimento 0.0.0-wip.3
É feito o merge da tarefa B em develop de uma branch feature 0.0.0-wip.4
Primeiro 'minor release'! Uma Branch é criada a partir de develop (release/0.1.0) e reseta o contador da compilação 0.1.0-rc.1
Mais um commit foi necessário 0.1.0-rc.2
Para manter o desenvolvimento sincronizado, fizemos o merge da branch 'release' de volta, criando um commit de mesclagem 0.1.0-wip.3
Um membro da equipe faz um commit de um recurso C em develop 0.1.0-wip.4
Release em produção: fizemos o merge de release/0.1.0 em master e develop 0.1.0-release.5 0.1.0-wip.6
É feito um commit de uma pequena refatoração em develop 0.1.0-wip.7
Um bug crítico é relatado na produção; Criar uma branch hotfix hotfix/0.1.1 0.1.1-hotfix.1
É feito o merge da versão atualizada de volta para develop e assim evitar duplicação de tags (uma vez que o contador tem que ser redefinido) 0.1.1-wip.2
Enquanto isso, outro commit de refatoração em develop 0.1.1-wip.3
O hotfix é finalizado 0.1.1-hotfix.4
A ser feito o merge para master e develop 0.1.1-release.5 0.1.1-wip.6
É feito o merge de outra branch de feature em develop 0.1.1-wip.7
Outra minor release. Criaremos a branch release/0.2.0 de develop e resetamos o contador da compilação (build) 0.2.0-rc.1

Conclusão

Pode ficar confuso de início, se não estiver familiarizado com o processo. Mas nada melhor que a prática. Então, crie o seu repositório de testes e comece a praticar. Tendo mais exemplos para ilustrar, estarei atualizando esse artigo ou criando um novo sobre o assunto. Feedbacks e novos cenários, são bem-vindos.