Gostaria de começar contextualizando um pouco sobre sistemas de gerenciamento de versões. No momento em que escrevo existem mais sistemas desse tipo do que eu poderia descrever (como Git, Team Foundation Vercion Control – TFVC -, Mercurial, SVN, etc) e pode ser que no momento em que você esteja lendo tantos outros tenham surgido, a discussão sobre qual é o melhor pode ser acompanhada em tempo real em outros locais ai a fora na internet. Mas um ponto central rege as funcionalidades de todos estes sistemas: garantir que desenvolvedores trabalhem na versão correta do código e que a versão mais estável seja publicada em produção sem a interferência de funcionalidades ainda não testadas.

Então, por que Git?

Como desenvolvedor iniciei minha carreira trabalhando com o bom e velho Source Safe tendo, naquele tempo, me beneficiado das vantagens e sofrido muito com as desvantagens. Um pouco depois quando surgiu o Team Foundation Server e o seu mecanismo de gerenciamento de versões, o TFVC, tive o primeiro contato com as dificuldades que trabalhar de forma colaborativa em um mesmo arquivo poderiam trazer – pela primeira vez me deparei com um merge. Pouco tempo depois isso se tornou algo natural para mim, mas ainda sim sofri até pouco tempo com perda de informações e horas e mais horas de trabalho duro para garantir que não iria deixar nada que algum colega tinha feito para trás – isso tudo pela abordagem de merge tardio que o TFVC traz e o tão famigerado Merge Hell.

Cuidado com merges, eles podem morder!

Com a entrada do Git no meu workflow houve uma quebra de paradigma, pois com ele as operações de branching e merging são extremamente simples, e pela natureza constante deste tipo de atividade elas deixam de ser tão amedrontadoras – entramos no modelo de merge antecipado e frequente. Um outro ponto de quebra – que mudou minha vida – é a questão de o Git trabalhar de forma descentralizada, permitindo que cada desenvolvedor tenha uma cópia local do repositório possibilitando o trabalho independente de conexão com o servidor central. Existem outras razões que me levam a ter o git como “o matador”, que são: a ampla utilização; disponibilidade de hosts, com grandes player como GitHub, GitLab e Bitbucket; e a real integração nas mais diversas plataforma e IDEs.

O Git trabalha de forma descentralizada, permitindo que cada desenvolvedor tenha uma cópia local do repositório possibilitando o trabalho independente de conexão com o servidor central.

Vamos aos tipos de workflow!

Agora que já temos um ideia central sobre a razão de utilizarmos um sistema de gerenciamento de versões e o motivo de o título iniciar com Git, vamos ao que interessa!

Existem diversas formas de organizar a política de branches para um determinado projeto, e cada projeto dentro de uma grande empresa pode exigir uma forma totalmente distinta de controle. Aqui apresentarei os mais comuns para serem utilizados como ponto de partida na definição da sua política. Lembre-se que não estou estabelecendo regras rígidas, apenas um guia para que você possa tomar a melhor decisão – procure escolher o melhor ou o melhor aspecto de cada um para atender a sua demanda.

Não se prenda a um único workflow, escolha o melhor de cada um.

Workflow Centralizado

Naturalmente o ponto de partida para equipes que trabalham com sistemas de gerenciamento de versões centralizados (como TFVC e SVN), pois facilita a transição para as ferramentas do Git sem que seja necessário modificar o workflow já utilizado pela equipe de desenvolvimento.

Mesmo com poucas mudanças no dia a dia, este tipo de workflow já se mostra bastante vantajoso por permitir que os desenvolvedores passem a se beneficiar do modelo distribuído – tendo uma cópia local e deixando de depender de uma conexão direta com o servidor central, fazendo isso somente quando conveniente. Como um bonus os desenvolvedores ganham acesso a todo o modelo de branching e merging do Git, extremamente robusto e confiável.

O modelo de branching e merging do Git é extremamente robusto e confiável.

Este workflow funciona de forma bem simplificada, onde um repositório central servirá como o ponto único de entrada para todas as mudanças do projeto, com o branch principal de nome master e todos os desenvolvedores realizando commits nesto mesmo branch – este workflow não exige nenhum outro branch.

Na linha do tempo: (1) os desenvolvedores iniciam pelo clone do repositório central; (2) Em suas cópias locais eles realizam modificações; (3) Ao finalizar as modificações executam os commits (assim como antes), mas desta vez as alterações são armazenadas localmente – os desenvolvedores estão totalmente isolados do repositório central; (4) Quando necessário, os desenvolvedores sincronizam suas modificações locais com o repositório central por meio de um push. Este push mencionado no passo (4) faz com que todo o branch master local seja enviado para o repositório central.

Em casos de conflitos com o repositório central, o Git sempre o tratará como sagrado e imutável e recusará qualquer push que tenha uma linha do tempo divergente, impedindo que qualquer desenvolvedor sobrescreva um commit oficial inadvertidamente. Felizmente o Git disponibiliza todas as ferramentas necessárias para que os desenvolvedores possam se manter atualizados e sincronizados com o repositório central (fetch e rebase), e caso durante um processo de rebase o desenvolvedor caia em uma situação de conflitos o Git pausará e permitirá que o desenvolvedor realize os merges necessários – impedindo a perda de trabalho já realizado.

Workflow de Branch de Funcionalidade

Um segundo passo para dentro do Git, pois permite que os times – já familiarizados com os comandos e processos do Workflow Centralizado – aumentem seu poder colaborativo tendo um branch dedicado para cada nova funcionalidade. Tendo estes novos branches os times podem realizar uma análise muito mais profunda das modificações que serão integradas no branch master.

O ponto base deste workflow é garantir que o branch master sempre tenha uma versão confiável de código e que múltiplas equipes consigam trabalhar de forma harmonica em suas novas funcionalidades, sem que modificações ainda não completamente testadas sejam incorporadas ao repositório central. Trazendo a funcionalidade de pull request o Git permite ainda que, em conjunto com os branches, os desenvolvedores iniciem discussões sobre uma determinada funcionalidade ou pontos de falhas dentro dela.

O pull request é uma ferramenta poderosa para que o time possa conhecer o trabalho de cada integrante.

Este workflow funciona de forma um puco menos simplificada, onde se mantem o uso de um repositório central e do branch master como principal. O ponto de mudança vem com os commits agora sendo não mais realizados neste branch, mas sim em branches de funcionalidades criados pelos desenvolvedores.

Na linha do tempo: (1) os desenvolvedores iniciam pelo clone do repositório central; (2) Em suas cópias locais criam um novo branch para a funcionalidade que iniciarão o desenvolvimento; (3) realizam as modificações; (4) realizam os commits locais; (5) Quando necessário, os desenvolvedores sincronizam sua modificações locais com o repositório central por meio de um push do branch da funcionalidade (permitindo inclusive que outros desenvolvedores tenham acesso às suas modificações); (6) Quando concluída a funcionalidade é criado um pull request para o branch master.

Não há problemas em armazenar inúmeros branches de funcionalidades no repositório central, inclusive este é um modo muito conveniente de se ter um backup das modificações locais.

Neste workflow os conflitos são tratados no momento da aceitação/processamento de um pull request. Diferente do workflow centralizado, as modificações não são integradas imediatamente no branch master, mas sim é iniciado um processo onde normalmente um ou mais responsáveis pelo repositório central avaliam as modificações realizadas, é aberta a oportunidade para que outros membros do time expressem suas opiniões e são formalizados os aceites. Assim que um pull request é aceito as modificações realizadas no branch da funcionalidade são integradas ao branch master.

Workflow Gitflow

Até aqui vimos como gradativamente podemos aprimorar o processo de gestão dentro de um sistema de gerenciamento de versões descentralizado – o Git – mesmo fazendo uso de um workflow centralizado. Com o workflow de branch de funcionalidade temos um modelo mais flexível para desenvolvimento de um projeto, mas em projetos que possuem equipes grandes com inúmeras iterações paralelas acontecendo este modelo pode se mostrar flexível demais – nestes casos é importante atribuir responsabilidades mais específicas para diferentes tipos de branches. O Gitflow vem como uma padronização para atender este tipo de requisito, definindo regras para a gestão de funcionalidades, releases e manutenções.

O padrão Gitflow foi apresentado por Vincent Driessen da nvie em seu artigo intitulado A successful Git branching model, onde foi definido uma padronização de branches voltada para o release do projeto. Embora seja mais complexo que os workflows anteriores, traz um framework muito mais robusto para a gestão de versões de grandes projetos, ainda sim mantendo os benefícios que obtemos pelo workflow de branches de funcionalidade – pull requests, experimentos isolados e colaboração eficiente.

Apresentado por Vincent Driessen da nvie o Gitflow veio para turbinar o já tão consagrado workflow de branch de funcionalidade.

Ainda fazendo uso de um repositório central como um canal de comunicação entre os desenvolvedores e mantendo o modo de trabalho local – com pushes – apresentado anteriormente, o Gitflow estabelece quatro novos grupos de branches:

Branches de Histórico

Ao invés de ter apenas um branch principal – o master – é estabelecido um novo – o develop. Aqui as responsabilidades ficam bem claras, o master é responsável por armazenar o histórico oficial de releases e o develop por armazenar as integrações entre as funcionalidades. Aqui vale ressaltar que cada commit no master deve receber uma tag com o número da versão que aquele commit representa.

Branches de Funcionalidade

Muito parecido com o que vimos no workflow de branch de funcionalidade, cada funcionalidade deve ser isolada e iterada em seu único branch. Mas aqui temos uma mudança chave, ao invés de a derivação ser feita do branch master ela passa a ser feita do develop e quando concluídas passam a terem suas modificações integradas também no develop.

Branches de Release

Assim que o branch develop atinge um número suficiente de features integradas ou chega próximo de uma data pré estabelecida, um novo branch de release é criado. A partir desta criação é iniciado um novo ciclo de release e novas funcionalidades não podem mais ser adicionadas – apenas correções de erros, documentação e outras tarefas orientadas para o release podem ser realizadas neste novo branch. Quando uma nova versão está pronta para ser implantada ela é integrada ao branch master – onde também é definida uma tag com o número da nova versão – e adicionalmente as correções realizadas durante a estabilização da versão são integradas ao branch develop.

A partir da criação do release, novas funcionalidades não podem mais ser adicionadas.

Branch de Manutenção

Também conhecido como hotfix os branches de manutenção devem ser utilizados para a execução de rápidas correções em ambiente produtivo. Este é o único grupo de branches que devem ser derivados diretamente do master e assim que as correções estão completas devem ser integrados novamente na master – sendo definida a nova tag para a correção – e adicionalmente na develop. O principal objetivo deste grupo de branches é permitir que os desenvolvedores envolvidos em uma correção não sofram impactos dos demais, que não impactem os demais e que as correções possam ser implantadas sem que haja a necessidade de se esperar um novo ciclo de release.

Conclusão

Aparentemente teríamos uma comparação entre os workflows, e isso era proposital. Sempre tentamos achar a melhor receita para resolver todos os problemas – a tal bala de prata – e com este texto quis te trazer um caminho mais tranquilo com um destino bem claro: ter um processo de gestão de versões muito mais robusto e padronizado. Vale lembrar que aqui não estou querendo apresentar regras rígidas de trabalho ou te convencer a seguir o “meu caminho”, existem muitos outros flows por ai e cada um vai trazer diferentes benefícios e dificuldades (inclusive tenho planos de detalhar melhor em outro post o Forking Workflow, que tem feito tanto sucesso com o Github).

Aproveite esse, vamos dizer, passo a passo para o Gitflow e comece do wokflow que melhor se encaixa na sua realidade atual. Depois que tiver implantado o processo ou enquanto estiver no caminho, nos conte suas descobertas e dificuldades nos comentários – vou ficar muito feliz em poder ajudar!

Referências

  1. Commit Often, Perfect Later, Publish Once: Git Best Practices
  2. Comparing Workflows
  3. A successful Git branching model