Como guias versus espaços, estratégias de branching representam um daqueles tópicos emocionantes que desencadeiam debates acalorados tanto online quanto offline.
Embora existam muitas opiniões fortemente defendidas sobre a melhor abordagem, como acontecem com muitas coisas no desenvolvimento de software, a resposta certa depende do contexto. Com isso em mente, vamos ver o que são estratégias de branching e como elas se relacionam com CI/CD.
Simplificando, uma estratégia de branching é o acordo de sua equipe sobre como e quando criar e mesclar branchs no controle de versão. A forma como você configura seu sistema de controle de versão e usa branches afetará como você configura seu pipeline de CI/CD e, por isso, é importante escolher um modelo que atenda às suas necessidades.
As estratégias de branching tornaram-se uma consideração para as equipes de desenvolvimento com o aumento da popularidade dos sistemas de controle de versão distribuídos, particularmente o Git, que tornou a branching mais fácil.
Com sistemas distribuídos, existem várias cópias do repositório e, portanto, várias fontes da verdade (embora seja comum as equipes designarem uma cópia central ou primária). Você e os membros da sua equipe trabalham em suas alterações em paralelo nas suas cópias do repositório, compartilhando seu trabalho por meio do envio de alterações para outras cópias do mesmo repositório.
O Git transformou a criação de branches e a mesclagem de submissões de diferentes branches em um exercício muito leve. No Git, um branch é apenas uma submissão (ou conjunto de submissões) rotulado com um nome específico. Branches são ideais para conter um conjunto de alterações, como trabalhar em um novo recurso ou um experimento.
Você pode então compartilhar suas alterações enviando o branch para outro repositório e/ou mesclando-o com outro branch (como o master) para combiná-lo com o resto da base de código. Você também pode descartar as alterações se não concordar com elas. Quando você mescla dois branches, o Git se encarrega de alinhar as submissões em cada um deles e evita grande parte da complexidade associada à mesclagem em outros sistemas de controle de versão.
Com a integração contínua, o foco é fazer com que todos em sua equipe de desenvolvimento submetam suas alterações com frequência. Isso significa que você pode testar regularmente se tudo está funcionando conforme o esperado, em vez de passar semanas ou meses tentando integrar diferentes fluxos de trabalho após a conclusão da codificação. Por sua vez, é possível lançar atualizações de software com mais frequência, revelando todos os benefícios da entrega e implantação contínuas.
Decidir onde as mudanças devem ser confirmadas, quando builds e testes automatizados devem ser executados e de onde as atualizações devem ser lançadas é o ponto em que o uso de branches interage com a CI/CD. A abordagem mais simples, pelo menos conceitualmente, é evitar branches por completo. No desenvolvimento baseado em troncos, todos submetem as alterações regularmente no branch master em um repositório central, mantido em um estado lançável e frequentemente implantado em produção.
Embora o desenvolvimento baseado em troncos possa funcionar de maneira muito eficaz, principalmente se você tiver uma configuração de CI/CD madura e estiver executando uma implantação contínua em um sistema hospedado, ele também apresenta alguns desafios. As estratégias de branching fornecem maneiras alternativas de gerenciar alterações de código, com diferentes benefícios e desvantagens. Veja a seguir algumas das alternativas mais comumente usadas por equipes de desenvolvimento que executam CI/CD.
Como o nome sugere, branches de recursos são criados para manter recursos individuais separados do restante da base de código. Manter o trabalho em andamento fora do branch master pode facilitar manter o master em um estado implantável e, se você estiver implantando diretamente do master em vez de um branch de lançamento (veja abaixo), evita as chances de que uma funcionalidade inacabada seja implantada em produção. Você ainda pode compartilhar seu trabalho com o restante de sua equipe, enviando seu branch ao repositório central (se tiver nomeado um) ou para qualquer outro repositório.
A principal desvantagem dos branches de recursos ( e as críticas frequentemente dirigidas a eles por defensores do desenvolvimento baseado em troncos) é que, ao atrasar a integração das alterações até que o recurso esteja “completo”, você perde os benefícios da integração contínua. Esses riscos mesclam conflitos e introduzem bugs mais complexos que demoram mais tempo para corrigir do que se as alterações tivessem sido confirmadas iterativamente.
Você pode atenuar esses problemas configurando seu servidor de CI para executar compilações automatizadas e testes em branches de recursos, bem como no master (ou em qualquer branch que você usar para preparar lançamentos). Isso garante que você obtenha o benefício de feedback imediato sobre o que está sendo construído, ao mesmo tempo em que reduz o risco de problemas que possam surgem ao mesclar as alterações.
Uma maneira de minimizar os conflitos de mesclagem é manter os branches de recurso de curta duração, até um ou dois dias, no máximo. Outra opção é rebasear o branch sobre o master ou mesclar as alterações do master regularmente. Isso atualiza seu branch de recursos com todas as outras alterações submetidas com o master. No entanto, se você tiver um grande número de branches de recursos simultâneos, todas atrasando submissões para o master, ainda há riscos de conflitos.
Enquanto branches de recursos fornecem uma maneira de gerenciar o trabalho em andamento, branches de lançamento são usados para “fortalecer” as alterações antes do lançamento. Branches de lançamento são adequados para um modelo de entrega contínua, em que as atualizações são entregues em intervalos, em vez de assim que estiverem prontas, e facilitam o suporte a várias versões em produção.
Com um fluxo de trabalho de branch de lançamento, uma vez que as alterações planejadas para uma determinada versão estejam prontas, um branch de lançamento contendo as alterações relevantes é criada (seja do master ou de outro branch de desenvolvimento), após o qual nenhum recurso adicional é incorporado. Enquanto isso, o desenvolvimento de recursos planejados para outras versões pode continuar a ser mesclado com o master ou em outro lugar.
Builds de branch de lançamento são então submetidos a uma série de testes automatizados e quaisquer correções de bug são feitas no branch de lançamento, seguido por mais rodadas de testes até que você esteja pronto para o lançamento. Essas correções de bugs também devem ser aplicadas de volta ao branch master para garantir que sejam incluídas em versões futuras do produto.
Manter seus branches de lançamento pelo tempo que você precisar para oferecer suporte a cada versão de seu software torna muito mais fácil implantar correções para versões antigas.
Quando uma atualização é necessária, ela pode ser desenvolvida em um branch de hotfix ou no master e testada normalmente e, em seguida, aplicada ao branch de lançamento (por exemplo, por meio de uma seleção seletiva).
Em seguida, ela será executada por meio do pipeline de CI/CD nesse branch para garantir que não haja problemas nessa versão antes de implantar a alteração. Como alternativa, você pode fazer o trabalho diretamente no branch de lançamento e aplicá-lo de volta ao master, conforme aplicável.
Branches de hotfix operam de forma semelhante a branches de recursos, mas vale a pena mencioná-los para fins de abrangência completa. Um branch de hotfix visa colocar uma correção de bug para produção o mais rápido possível.
Você pode criar um branch de hotfix do master ou de um branch de lançamento, dependendo de onde você implantar. Assim como acontece com os branches de recursos, você pode optar por executar alguns dos elementos de CI/CD no seu branch de hotfix antes de mesclá-lo com o branch master ou de lançamento, onde pode passar por mais testes automatizados antes do lançamento.
Vimos algumas das maneiras mais comuns de usar branches no seu workflow de CI/CD, mas existem muitas outras variações por aí.
O mais importante é encontrar uma estratégia que funcione para o seu contexto específico. Adotar uma mentalidade de DevOps de melhoria contínua e permanecer aberto a diferentes opções permitirá que você continue ajustando sua abordagem às suas necessidades conforme sua prática de CI/CD amadurece.