Rollback strategies: revertendo deploys com git revert ou tags

Em ambientes de produção, a capacidade de reverter uma mudança problemática rapidamente é tão importante quanto a habilidade de fazer deploys. Git oferece duas estratégias principais para rollback: git revert e o uso de tags. Cada uma atende a cenários específicos, e a escolha errada pode transformar um problema simples em uma catástrofe de histórico. Este artigo explora ambas as abordagens sob a perspectiva de Git, com exemplos práticos e boas práticas para equipes que precisam de deploys seguros.

1. Fundamentos do Rollback com Git

Antes de escolher uma estratégia, é crucial entender a diferença entre git revert e git reset. git reset move o ponteiro do branch para trás, descartando commits do histórico. Isso reescreve a história — algo perigoso em branches compartilhados como main ou master. Se outro desenvolvedor já puxou esses commits, o repositório ficará inconsistente.

git revert, por outro lado, cria um novo commit que desfaz as alterações de um commit específico. O histórico permanece intacto, e todos os colaboradores podem puxar a reversão sem conflitos de sincronização.

Já o uso de tags para rollback não altera o histórico — você simplesmente volta a trabalhar a partir de um ponto conhecido. Tags são como marcadores imutáveis: uma vez criadas, apontam para um commit específico para sempre (a menos que sejam forçadas, o que é desaconselhado).

2. Estratégia com git revert: Revertendo Commits Específicos

A sintaxe básica é direta:

git revert <commit-hash>

Isso abre o editor para a mensagem do commit de reversão (geralmente "Revert ''") e cria um novo commit. O resultado é um histórico linear onde a reversão aparece como uma mudança legítima.

Para reverter múltiplos commits consecutivos, use a faixa de commits:

git revert HEAD~3..HEAD

Isso reverte os três commits mais recentes, criando três novos commits de reversão (um para cada). Se preferir um único commit de reversão, use --no-commit:

git revert --no-commit HEAD~3..HEAD
git commit -m "Revertendo últimos 3 commits"

Lidando com conflitos

Conflitos podem ocorrer se houver dependências entre os commits revertidos e o estado atual. O Git pausa o processo e permite que você resolva manualmente:

git revert <commit>
# CONFLITO! Resolva os arquivos, depois:
git add .
git revert --continue

3. Estratégia com Tags: Pontos de Restauração Rápidos

Tags são ideais para rollbacks emergenciais. Crie tags semânticas para cada release:

git tag -a v1.2.3 -m "Release 1.2.3 - funcionalidade X"
git push origin v1.2.3

Para reverter para uma versão anterior:

git checkout tags/v1.2.2 -b hotfix/v1.2.2

Isso cria um novo branch a partir do ponto marcado. Você pode aplicar correções e fazer deploy desse branch. Depois, mescle de volta para main com um merge commit.

A grande vantagem é a velocidade: não é necessário calcular quais commits reverter. Basta apontar para a tag e seguir. A desvantagem é que você perde o histórico de mudanças entre a tag atual e a anterior — o rollback não fica registrado como uma reversão explícita.

4. Rollback de Merge Commits (Pull Requests)

Reverter um merge commit exige cuidado especial. Merge commits têm dois pais: o pai principal (o branch de destino, geralmente main) e o pai secundário (o branch mesclado, como feature). Para reverter mantendo a linha principal, use a flag -m 1:

git revert -m 1 <merge-commit-hash>

O -m 1 diz ao Git: "reverta as mudanças, mas mantenha o histórico da linha principal". Sem essa flag, o Git não sabe qual pai considerar e retorna erro.

Cuidado com reversões encadeadas

Se você reverter um merge commit e depois quiser reverter essa reversão, o Git pode reclamar de "já revertido". Use git revert <hash-do-revert> normalmente — o Git criará um novo commit que restaura as mudanças originais. Isso é seguro e mantém o histórico linear.

5. Workflow de Rollback com Git Flow e Releases

Em um fluxo Git Flow típico, o rollback em produção deve ser tratado com cuidado para não perder o trabalho em andamento no branch develop.

Cenário: você fez deploy da release v2.0.0 em main, mas um bug crítico foi descoberto. A equipe já está trabalhando em v2.1.0 no develop.

Passo 1: Reverter em main:

git checkout main
git revert -m 1 <merge-commit-da-release>
git push origin main

Passo 2: Sincronizar develop:

git checkout develop
git merge main

Agora develop contém a reversão. Se a equipe precisar dos commits da release revertida, eles podem usar git cherry-pick para selecionar apenas as correções necessárias:

git cherry-pick <commit-de-correcao>

Isso evita reintroduzir o bug enquanto mantém o progresso.

6. Automação e Scripts para Rollback Rápido

Um script simples para rollback via revert:

#!/bin/bash
COMMIT_TO_REVERT=$1
git checkout main
git pull origin main
git revert --no-commit $COMMIT_TO_REVERT
git commit -m "Rollback: revertendo $COMMIT_TO_REVERT"
git push origin main

Para rollback via tag, um script pode aceitar o nome da tag:

#!/bin/bash
TAG=$1
git checkout tags/$TAG -b hotfix/$TAG
# Aplique correções, faça deploy
git checkout main
git merge hotfix/$TAG
git push origin main

Em pipelines de CI/CD, você pode disparar rollbacks automaticamente. Por exemplo, no GitHub Actions, um workflow pode ser acionado por um comentário em uma issue: /rollback v1.2.2. O script então executa o checkout da tag e faz deploy.

7. Erros Comuns e Como Evitá-los

Erro 1: Esquecer de reverter em branches de desenvolvimento. Se você reverteu em main, mas não mesclou em develop, o próximo merge trará o bug de volta. Sempre sincronize após um rollback.

Erro 2: Conflitos inesperados ao reverter commits antigos. Quanto mais tempo passa entre o commit original e o revert, maior a chance de conflitos. Resolva com cuidado e teste exaustivamente.

Erro 3: Rollback sem comunicação. Se a equipe já puxou a mudança problemática, eles precisam saber que ela foi revertida. Use notificações no Slack, e-mail ou no próprio repositório.

Erro 4: Usar git reset em branches compartilhados. Isso força todos a fazer git push --force e pode corromper o histórico. Nunca faça isso em main ou develop.

8. Comparação Final: Quando Usar Cada Estratégia

git revert é a escolha padrão para equipes que valorizam um histórico limpo e colaborativo. Cada reversão é registrada como um commit, facilitando auditorias e rastreamento. Ideal para deplays em ambientes de produção onde múltiplos desenvolvedores trabalham no mesmo branch.

Tags são melhores para rollbacks emergenciais e deploys frequentes, especialmente em sistemas de microserviços ou CD. A velocidade de apontar para um ponto conhecido supera a necessidade de um histórico detalhado de reversões.

A decisão final depende da maturidade da equipe e da criticidade do sistema. Times maduros geralmente combinam ambas: usam tags para releases e git revert para correções específicas. O importante é ter um processo documentado e testado — um rollback bem-sucedido é aquele que ninguém percebe que aconteceu.

Referências