Trabalhando em Equipe com Git Flow

[63] Trabalhando em Equipe com Git Flow

Git Flow como modelo de organização de branches: os papéis de main e develop, o ciclo de feature, release e hotfix, o que cada comando do plugin faz por baixo em Git puro, o papel do --no-ff e quando o modelo é excessivo diante de GitHub Flow e Trunk-Based Development.
DevOps

9 min de leitura

O Git oferece branches, mas não diz como usá-las. Em uma equipe pequena sem convenção, rapidamente surgem dúvidas: onde fica o código que vai para produção? Como se trabalha em duas funcionalidades ao mesmo tempo? O que acontece quando um bug crítico precisa ser corrigido enquanto uma nova versão ainda está em desenvolvimento?

O Git Flow é um modelo de organização de branches que responde a essas perguntas. Foi proposto por Vincent Driessen em 2010 e se tornou um dos padrões mais adotados pela indústria. Não é o único modelo — existem alternativas como GitHub Flow e Trunk-Based Development — mas o Git Flow é o mais completo para entender os princípios antes de avaliar as alternativas.

As Cinco Branches do Git Flow

O modelo define dois tipos de branches: as permanentes, que existem durante toda a vida do projeto, e as temporárias, que nascem para uma tarefa e são removidas após o merge.

Branches permanentes:

  • main — contém o código que está em produção. Cada commit nessa branch representa uma versão lançada.
  • develop — o ponto de integração contínua. Todas as funcionalidades concluídas chegam aqui antes de ir para produção.

Branches temporárias:

  • feature/* — para desenvolver novas funcionalidades
  • release/* — para preparar uma nova versão para produção
  • hotfix/* — para corrigir bugs críticos diretamente em produção

Instalando o Git Flow

A maioria das distribuições Linux oferece o git-flow como pacote:

sudo apt install git-flow   # Debian/Ubuntu

Inicializando em um repositório existente:

git flow init

O comando faz algumas perguntas sobre os nomes das branches — aceitar os padrões é a escolha correta na maioria dos casos.

Fluxo de uma Nova Funcionalidade

# Inicia uma feature branch a partir da develop
git flow feature start configurar-monitoramento

# O Git cria e já muda para a branch feature/configurar-monitoramento
# Trabalha-se normalmente com commits
echo "# Prometheus Config" > prometheus.yml
git add prometheus.yml
git commit -m "feat: adiciona configuração base do Prometheus"

# Quando a funcionalidade está pronta, finaliza-se
git flow feature finish configurar-monitoramento

O feature finish faz o merge de volta para develop, remove a branch de feature e volta para develop. Tudo em um único comando.

Preparando uma Release

Quando a develop tem um conjunto de funcionalidades prontas para ir a produção, cria-se uma branch de release:

# Inicia a release com o número de versão
git flow release start 1.2.0

Nessa branch, fazem-se apenas ajustes finais: atualização de número de versão, correções menores, atualização de changelog. Nenhuma funcionalidade nova entra aqui.

# Atualiza o arquivo de versão
echo "1.2.0" > VERSION
git add VERSION
git commit -m "chore: bump version to 1.2.0"

# Finaliza a release
git flow release finish 1.2.0

O release finish faz três coisas automaticamente:

  1. Merge na main (marcando o código de produção)
  2. Cria uma tag 1.2.0 na main
  3. Merge de volta na develop (para que as correções feitas na release não se percam)

Corrigindo Bugs em Produção com Hotfix

Imagine que um bug crítico foi descoberto em produção. Não é possível esperar o ciclo normal de desenvolvimento — a correção precisa ir direto para a main:

# Inicia o hotfix a partir da main
git flow hotfix start 1.2.1

# Corrige o bug
git add .
git commit -m "fix: corrige falha de autenticação em requests concorrentes"

# Finaliza
git flow hotfix finish 1.2.1

O hotfix finish faz merge tanto na main quanto na develop, garantindo que a correção também esteja presente no código em desenvolvimento.

Git Flow sem o Plugin

É perfeitamente possível seguir o modelo Git Flow sem o plugin, usando apenas os comandos nativos do Git. O plugin é um atalho — entender o que acontece por baixo é mais importante:

# Equivalente ao git flow feature start minha-feature
git checkout develop
git checkout -b feature/minha-feature

# Equivalente ao git flow feature finish minha-feature
git checkout develop
git merge --no-ff feature/minha-feature
git branch -d feature/minha-feature

O flag --no-ff (no fast-forward) força a criação de um merge commit mesmo quando o fast-forward seria possível. Isso preserva no histórico a evidência de que aquele conjunto de commits veio de uma feature branch — informação valiosa ao auditar o histórico.

Quando Usar Git Flow — e Quando Não Usar

O Git Flow brilha em projetos com ciclos de release definidos — aplicações com versões numeradas, bibliotecas, produtos com janelas de lançamento planejadas.

Ele é excessivo para equipes que fazem deploy contínuo — onde cada commit na branch principal pode ir a produção a qualquer momento. Nesses casos, modelos mais simples como o GitHub Flow (apenas main e feature branches) ou Trunk-Based Development (todos trabalham diretamente na main com feature flags) são mais adequados.

A escolha do modelo depende do ritmo de entregas da equipe e da maturidade do pipeline de CI/CD — assunto que será aprofundado no Módulo 4.

O Que Vem a Seguir

No próximo artigo será abordado o GitHub Actions — a ferramenta que transforma eventos no repositório em automações: testes que rodam a cada push, deploys que acontecem a cada merge na main, notificações automáticas. É onde Git e DevOps se conectam de forma concreta pela primeira vez.

Referências para Aprofundamento

Artigo original e evolução

Leitura complementar

  • Trunk Based Development — Site dedicado ao modelo de desenvolvimento baseado em trunk, com argumentos técnicos sobre escalabilidade e integração contínua.
  • Pro Git — Capítulo 3: Branching — Capítulo em português do Pro Git cobrindo o modelo interno de branches e merge do Git.

Prática

  • Learn Git Branching — Os níveis avançados do simulador cobrem merges complexos e rebase, que complementam o entendimento do Git Flow.

Exercícios

Exercício 1

Qual o papel da main e qual o da develop? Que pergunta essa separação permite responder que uma branch só não responderia?

Ver resposta

✓ Resposta: A main guarda o código que está em produção — cada commit nela representa uma versão lançada. A develop é o ponto de integração contínua: toda funcionalidade concluída chega ali antes de ir a produção. A pergunta que a separação responde é "o que exatamente está no ar agora?", e a resposta passa a ser um lugar único e confiável. Com uma branch só, código pronto e código publicado convivem misturados, e descobrir o que já foi entregue vira arqueologia de histórico.

Exercício 2

O git flow release finish 1.2.0 executa três operações. Quais são elas, e por que o merge de volta na develop é indispensável?

Ver resposta

✓ Resposta: Ele faz merge na main, cria a tag 1.2.0 nesse ponto e faz merge de volta na develop. O terceiro passo é indispensável porque a branch de release não é só uma passagem: nela foram feitos o bump de versão, o changelog e as correções de última hora. Sem o retorno à develop, esses commits morrem junto com a branch — e o bug corrigido às pressas durante a release reaparece intacto na versão seguinte, porque o desenvolvimento continuou de um ponto que nunca soube da correção.

Exercício 3

Por que um hotfix nasce a partir da main, e não da develop?

Ver resposta

✓ Resposta: Porque a develop contém funcionalidades que ainda não foram lançadas. Um hotfix que partisse dela levaria, no merge para a main, código não testado nem aprovado para produção — ou seja, resolveria um bug crítico introduzindo novidades inéditas no mesmo movimento, exatamente o oposto do que se quer sob pressão. Partindo da main, a correção contém precisamente o que está no ar mais o conserto, e nada além. E o hotfix finish faz merge nas duas branches, para que a correção não desapareça no próximo ciclo de desenvolvimento.

Exercício 4

O que a flag --no-ff faz, e por que o Git Flow a utiliza ao finalizar uma feature?

Ver resposta

✓ Resposta: Ela força a criação de um merge commit mesmo quando o fast-forward seria possível. Sem ela, a feature se dissolve no histórico: seus commits entram na develop indistinguíveis de commits feitos diretamente ali, e a informação de que aquilo era uma unidade de trabalho desaparece. Com --no-ff, o histórico preserva o agrupamento — dá para ver onde a feature começou e terminou, e desfazer o conjunto inteiro com um único git revert -m 1 em vez de caçar commit por commit.

Exercício 5

Em que situação o Git Flow é excessivo? Quais alternativas existem, e o que determina a escolha entre elas?

Ver resposta

✓ Resposta: Ele é excessivo em equipes que praticam deploy contínuo, onde cada commit na branch principal pode ir a produção a qualquer momento. Nesse ritmo, a develop e as branches de release/* viram etapas de espera que atrasam a entrega sem reduzir risco. As alternativas são o GitHub Flow — apenas main e feature branches — e o Trunk-Based Development, em que todos trabalham na main e o que ainda não deve aparecer fica atrás de feature flags. O que determina a escolha é o ritmo de entrega somado à maturidade do pipeline: quanto mais automatizado e confiável o CI/CD, menos camadas de branch são necessárias para dar segurança.

Exercício 6

Traduza os dois comandos do plugin para Git puro. Por que vale conhecer o equivalente nativo?

git flow feature start minha-feature
git flow feature finish minha-feature
Ver resposta

✓ Resposta: O start equivale a git checkout develop seguido de git checkout -b feature/minha-feature. O finish equivale a git checkout develop, git merge --no-ff feature/minha-feature e git branch -d feature/minha-feature. Vale conhecer o equivalente por dois motivos práticos: o plugin não está instalado em todo lugar — servidor de CI, container enxuto, máquina de um colega — e, quando algo falha no meio de um finish, só quem conhece as etapas nativas consegue identificar em qual delas parou e retomar dali, em vez de rodar o comando de novo e piorar o estado.

Comentários

Mais em DevOps

Testes Automatizados no Pipeline: Qualidade sem Atrito
Testes Automatizados no Pipeline: Qualidade sem Atrito

A pirâmide de testes aplicada ao pipeline: a proporção 70/20/10 e o antipadrão…

AWS na Prática: EC2, VPC e IAM em Profundidade
AWS na Prática: EC2, VPC e IAM em Profundidade

Os três serviços mais fundamentais da AWS em profundidade: famílias de…

Terraform + Ansible: Do Provisionamento à Configuração
Terraform + Ansible: Do Provisionamento à Configuração

A fronteira entre provisionar e configurar, e como cruzá-la sem trabalho…