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 '
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
- Git - git-revert Documentation — Documentação oficial do comando
git revert, incluindo opções como-mpara merge commits e--no-commit. - Git - git-tag Documentation — Documentação oficial sobre criação, listagem e gerenciamento de tags no Git.
- Atlassian - Git Revert vs Reset — Tutorial comparativo entre
git revertegit reset, com exemplos práticos para rollback. - GitHub - Reverting a Pull Request — Guia oficial do GitHub sobre como reverter pull requests, incluindo o uso de
git revert -m. - Git Flow - Vincent Driessen — Artigo seminal sobre Git Flow, que descreve workflows de release e rollback com branches e tags.