Saltar para o conteúdo

Estratégias de Branching no Git

Fonte: Wikiversidade

Branching é uma feature muito importante dos VCS (Versioning Control Systems), pois permite ao desenvolvedor que modifique o projeto em que está trabalhando de forma a não afetar a linha principal de produção.[1]

Quando estamos trabalhando com branching (ou com o git, de forma geral), é importante estabelecer uma padronização na forma como acrescentamos novo código no repositório compartilhado por uma equipe, seja no ato de realizar um commit ou na criação de uma nova branch. Essas convenções têm como objetivo evitar futuros conflitos de entendimento do programador em relação às mudanças que ele próprio realiza no repositório, como também permitir com que a comunicação da equipe que está trabalhando no projeto seja mais fluida.

Tome como exemplo os contribuidores A e B de um projeto que utiliza as funcionalidades de branching do git. O contribuidor A decide trabalhar com o branching de tal forma que seja aberta uma nova branch para qualquer mudança que se queira realizar no código, independente de serem alterações no código principal ou em funcionalidades periféricas, para depois realizar um merge na branch principal, evitando commits diretos nela. B, por sua vez, decide reservar branches para, apenas, hotfixes, realizando commits diretos na branch principal para quaisquer outras alterações.

Nesse cenário, A não saberia diferenciar imediatamente, ao olhar a branch principal, quais mudanças feitas por B foram funcionalidades novas, e quais afetaram o código mais importante do projeto, enquanto B poderia ter seu desenvolvimento de alguma parte do programa interrompido por um grande merge feito por A, pois esteve alterando muitas partes do código conforme B fazia pequenos commits.

A e B discutindo estratégias de organização do git.

Dado a importância de manter uma estrutura comum de desenvolvimento, vamos conhecer dois tipos de estruturas de branching, bem como os critérios usados para escolher entre elas de acordo com a necessidade.

Estruturas de organização

[editar | editar código-fonte]

Mainline Development

[editar | editar código-fonte]

Nesta estrutura de organização com git, trabalhamos com uma quantidade pequena ou inexistente de branches, ou seja, com o desenvolvimento pautado em pequenos commits diretamente na main branch, dando prioridade à rapidez com a qual as modificações (de menor escala) são feitas.

Uma vantagem em potencial desse tipo de estrutura é a ausência de grandes ramificações do desenvolvimento, que podem o deixar confuso e difícil de navegar, reduzindo a necessidade de monitorar várias branches. Por outro lado, como a maior parte dos commits são feitos diretamente na main, é necessário fazer testagens frequentes para evitar situações em que um bug se alastra por diversos estados da main e outras funcionalidades precisam ser corrigidas por terem sido desenvolvidas em versões posteriores ao surgimento do bug.

Esta estrutura não escala tão bem com grandes equipes de desenvolvimento.

State, Release and Feature branches development

[editar | editar código-fonte]

Ao contrário do mainline development, essa estrutura de desenvolvimento propõe a ramificação do desenvolvimento em branches conforme necessário. As branches de State e Release são long-lived (a Release branch armazena o histórico de releases do projeto, ao passo que a de State armazena o estado atual de produção dele), enquanto as branches de Feature são short-lived, uma vez que servem para a implementação de funcionalidades no projeto sem afetar seu estado de produção, e são apagadas após a integração com a State branch. Por exemplo, um contribuidor num projeto de grande escala pode tentar desenvolver uma nova ferramenta para o programa principal por meio de uma branch de teste, sem interferir no estado atual do código-fonte mais central do programa.

Esse método de organização proporciona uma liberdade muito grande para a adição de features e correção de bugs ao longo do desenvolvimento do projeto, e a maior parte das mudanças definitivas na branch principal são feitas por meio de merges, minimizando ao máximo commits diretos nela.

Estratégias de Branching

[editar | editar código-fonte]

O trunk-based development deriva da ideia de mainline development, ou seja, é utilizada apenas uma branch, a main (master), onde todos os desenvolvedores do projeto fazem modificações diretamente (caso uma modificação em particular demore a ser finalizada, um contribuidor pode eventualmente criar uma branch para tal, apesar de ser um comportamento evitado). Como prevê o mainline development, o código deve ser cuidadosamente testado para que essa estratégia seja viável.[1]

Criado pela plataforma GitHub, o GitHub flow tem como características principais o uso de uma única long-lived branch (a main (master), que armazena o histórico de produção do projeto) em conjunto com diversas short-lived branches (as feature branches) cuja função é a implementação de funcionalidades no software sem que a linha de produção seja afetada diretamente, e que são apagadas após a integração com a main.[2]

Criado por Vincent Driessen em 2010,[3] o Gitflow, em oposição ao Trunk-Based Development, foca no uso de diversas branches (tanto long-running quanto short-lived) com funções e interações entre si bem definidas, e commits maiores.[4]. As ramificações que compõem essa estratégia de branching são:

Main (master)

[editar | editar código-fonte]

Uma long-lived branch, a main armazena o histórico oficial de releases do projeto. Desse modo, todo commit feito nela deve conter uma tag com o número da versão.

Outra long-lived branch, a develop contém o histórico completo (de produção) do projeto, isto é, serve como uma branch de integração para as features do software em questão.

Ramificações feature são short-lived branches criadas para a implementação de features no projeto. Essas ramificações devem partir da develop, e serem integradas novamente a ela assim que a funcionalidade a ser adicionada estiver pronta. É importante ressaltar que a interação entre a develop e as feature branches é o que compõe o GitHub flow.

As release branches são também short-lived, e criadas a partir da develop quando esta acumula features o suficiente para uma release (ou quando uma data de release se aproxima). Como tal, a partir do momento de criação desse tipo de branch, um ciclo de release é iniciado, de modo que nenhuma feature nova é adicionada a partir desse ponto, apenas trabalho relacionado a bug fixes, documentação, entre outros, é realizado. Uma vez pronta a release, essa branch é integrada diretamente na main, e marcada com uma tag indicando o número da versão do projeto.

Branches hotfix são short-lived e servem para a manutenção ou correção rápida de erros em releases. Portanto, são derivadas da main (em oposição às feature e release, que derivam da develop), e, no momento em que a correção for feita, devem ser integradas tanto na main quanto na develop (ou na release, caso haja uma no momento). Por ser integrada diretamente à main, esta deve receber uma tag com um número atualizado da versão atual do projeto.

  1. 1,0 1,1 Ambrozinak, Paulina. "Git Branching Strategies". Tilburg Science Hub. https://tilburgsciencehub.com/topics/automation/version-control/advanced-git/git-branching-strategies/
  2. GitHub. "GitHub flow". https://docs.github.com/en/get-started/using-github/github-flow
  3. Driessen, Vincent. "A successful Git branching model". nvie.com.https://nvie.com/posts/a-successful-git-branching-model/
  4. "Gitflow workflow". Atlasian. https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow