DEV Community

Cover image for Como usar git-filter-repo para remover arquivos e segredos do histórico Git
Felipe Augusto
Felipe Augusto

Posted on

Como usar git-filter-repo para remover arquivos e segredos do histórico Git

Como usar git-filter-repo para remover arquivos e segredos do histórico Git

Quando um arquivo sensível ou uma chave vaza para o repositório, apagar o arquivo no commit atual não resolve o problema. O conteúdo continua acessível no histórico do Git. Nesses casos, a abordagem correta é reescrever todo o histórico do repositório.

Hoje, a ferramenta mais recomendada para esse tipo de limpeza é o git-filter-repo, inclusive apontada como substituta do antigo git filter-branch. O projeto exige Python 3.6+ e Git >= 2.24.0, e a versão publicada no PyPI no momento é a 2.47.0, liberada em 4 de dezembro de 2024 (o que consideramos ser bastante estável)

Neste artigo, vou mostrar como:

  • verificar se o Python está pronto no Windows;
  • instalar o git-filter-repo;
  • apagar arquivos do histórico;
  • substituir segredos no histórico;
  • publicar a nova árvore de commits;
  • orientar o restante do time após o rewrite;
  • conectar isso com um fluxo de prevenção usando Gitleaks no GitHub Actions.

Também deixo no final um vídeo seu no YouTube que complementa esse processo.


1. Verificando a versão do Python

No Windows, um jeito simples de listar as versões instaladas é:

py -0
Enter fullscreen mode Exit fullscreen mode

O git-filter-repo requer Python 3.6 ou superior como já falamos.

Se você não tiver uma versão compatível, instale uma versão atual do Python antes de continuar. A própria documentação do projeto observa que usuários Windows às vezes enfrentam problemas com aliases do Python e, nesses casos, pode ser necessário executar o script explicitamente com o interpretador Python.
Entenda esse alias, como as configuração da variável de ambiente para o path de onde o python esta instalado.


2. Documentando a instalação do git-filter-repo

A página oficial do pacote no PyPI é a referência mais prática para documentar a versão e a instalação do git-filter-repo. No momento, ela mostra a versão 2.47.0 e o comando base:

pip install git-filter-repo
Enter fullscreen mode Exit fullscreen mode

No entanto, a documentação oficial do projeto destaca instalação via pipx ou uv tool como caminhos recomendados para o pacote PyPI. Exemplo com pipx:

pipx install git-filter-repo
Enter fullscreen mode Exit fullscreen mode

Se você quiser apenas validar a instalação depois, pode testar:

git filter-repo -h
Enter fullscreen mode Exit fullscreen mode

Se no seu ambiente Windows o comando git filter-repo não funcionar diretamente, a própria documentação sugere chamar o script pelo Python:

python git-filter-repo --help
Enter fullscreen mode Exit fullscreen mode

3. Antes de mexer no histórico: clone limpo e cuidado com impacto

Reescrever histórico não é uma operação trivial. Ela altera hashes de commits, branches e tags reescritas. O git-filter-repo tem inclusive uma checagem de segurança voltada a uso em clone “fresco”, e o uso de --force serve justamente para contornar esse bloqueio quando você sabe o que está fazendo.

Por isso, a boa prática é:

  1. trabalhar em um clone separado;
  2. confirmar exatamente o que deve ser removido;
  3. avisar o time antes do push forçado;
  4. publicar a limpeza;
  5. orientar todos a sincronizar novamente o repositório local.

4. Descobrindo em que commit um arquivo entrou

Quando o problema é um arquivo grande, um artefato indevido ou um ZIP versionado por engano, vale primeiro descobrir onde ele apareceu no histórico:

git log --all --full-history -- "caminho/do/arquivo.zip"
Enter fullscreen mode Exit fullscreen mode

Esse comando ajuda a localizar os commits relacionados ao arquivo, entender o impacto da limpeza e até documentar o incidente.


5. Apagando um arquivo de todos os commits

Se a necessidade for remover completamente um arquivo do histórico, o comando é:

git filter-repo --path "caminho/do/arquivo.zip" --invert-paths
Enter fullscreen mode Exit fullscreen mode

As vezes vc pode ter problema no path, colocando um ./ na frente ou não - então por vezes vai precisar fazer mais de uma vez ate vc acertar - mas isso é um erro seu e não do pacote. Alerto sobre isso pq eu que uso muito o PowerShell Core, ao usar o tab para completar os caminhos path, o terminal pode fazer esse erro de colocar um ./ ou inverter uma barra, o que pode prejudicar a execução do comando - portanto tenha atenção nisso.

A lógica é simples:

  • --path indica o caminho afetado;
  • --invert-paths diz para remover esse caminho e manter o restante.

Se o problema for uma pasta inteira, o raciocínio é o mesmo. Exemplo:

git filter-repo --path "storybook-static/" --invert-paths
Enter fullscreen mode Exit fullscreen mode

6. Gerando análise antes ou depois da limpeza

Um comando muito útil para inspeção é:

git filter-repo --analyze --force
Enter fullscreen mode Exit fullscreen mode

Ele gera relatórios dentro de .git/filter-repo/analysis, o que ajuda a entender melhor paths, blobs e objetos do repositório.

Esse comando é especialmente útil quando:

  • você quer descobrir arquivos grandes;
  • suspeita de lixo histórico;
  • quer investigar quais caminhos mais pesam no repositório;
  • precisa de uma visão mais segura antes de sair removendo coisas.

7. Substituindo segredos do histórico com arquivo .gitfilter

Quando o problema é uma chave, token, senha ou segredo hardcoded, você pode usar --replace-text.

Exemplo de arquivo .gitfilter:

389123yunfg34iug348r739ht==>**REMOVIDA**
Enter fullscreen mode Exit fullscreen mode

Depois, execute:

git filter-repo --replace-text .gitfilter --force
Enter fullscreen mode Exit fullscreen mode

Esse processo percorre o histórico reescrevendo o texto encontrado. Para incidentes de segredo exposto, isso é muito útil porque você não precisa necessariamente remover o arquivo inteiro; em alguns cenários, basta substituir o valor comprometido.

Um ponto importante sobre arquivos começando com ponto

Aqui vale uma correção conceitual importante: arquivos com . no nome, como .gitfilter, .env ou .gitignore, não são “por definição” arquivos que não devem ser versionados. No Unix e em vários ambientes, eles são apenas arquivos “ocultos” por convenção. Alguns devem sim ser versionados, como .gitignore, .editorconfig e muitos arquivos de configuração do projeto. Outros, como .env, muitas vezes não devem. Então a regra prática é: sempre confira o .gitignore e a política do projeto antes de decidir. Isso evita transformar uma convenção em regra absoluta.


8. Exemplo completo de fluxo

Um fluxo simples para um incidente comum pode ser:

Caso A: apagar um arquivo indevido do histórico

git log --all --full-history -- "caminho/do/arquivo.zip"
git filter-repo --analyze --force
git filter-repo --path "caminho/do/arquivo.zip" --invert-paths
git push origin --force --all
git push origin --force --tags
Enter fullscreen mode Exit fullscreen mode

Caso B: substituir um segredo vazado

Crie o arquivo .gitfilter:

chave-antiga==>**REMOVIDA**
Enter fullscreen mode Exit fullscreen mode

Depois rode:

git filter-repo --analyze --force
git filter-repo --replace-text .gitfilter --force
git push origin --force --all
git push origin --force --tags
Enter fullscreen mode Exit fullscreen mode

9. Publicando a nova árvore de commits

Depois da limpeza, é necessário enviar a nova história para o remoto:

git push origin --force --all
git push origin --force --tags
Enter fullscreen mode Exit fullscreen mode

Esses comandos forçam a atualização das branches e tags reescritas. Isso é esperado, porque os hashes dos commits mudam quando o histórico é alterado.


10. O que o restante do time precisa fazer depois

Depois de um rewrite desses, o time precisa sincronizar o ambiente local com a nova história. Um fluxo objetivo para a branch principal é:

git fetch origin
git checkout main
git reset --hard origin/main
git clean -fd
Enter fullscreen mode Exit fullscreen mode

Esse conjunto de comandos:

  • busca a nova referência do remoto;
  • muda para a branch principal;
  • alinha o histórico local exatamente ao remoto;
  • remove arquivos e diretórios não rastreados.

Em alguns times, também vale orientar as pessoas a recriar branches locais derivadas de commits antigos, porque qualquer branch baseada na história anterior pode carregar referências inválidas ou até reintroduzir conteúdo removido.


11. Relacionando isso com Gitleaks no GitHub Actions

Limpar o passado é importante, mas o ideal é impedir reincidência. É aí que entra o Gitleaks.

O Gitleaks é uma ferramenta para detectar segredos em repositórios Git, e a ação oficial para GitHub Actions permite rodar varredura em pushes e pull requests.

Exemplo:

name: gitleaks

on:
  pull_request:
  push:
  workflow_dispatch:

jobs:
  scan:
    name: gitleaks
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Run Gitleaks
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

A conexão entre as duas ferramentas fica muito clara:

  • git-filter-repo corrige o passado;
  • Gitleaks ajuda a proteger o futuro.

Uma abordagem madura é usar os dois: primeiro saneia o histórico, depois adiciona validação contínua no pipeline para evitar que novos segredos cheguem ao repositório novamente.

Para conhecer mais sobre o projeto Gitleaks, acesse:

https://github.com/gitleaks/gitleaks


12. Erros comuns e observações práticas

Usar --force sem entender o impacto

O --force existe porque reescrever histórico é destrutivo e o git-filter-repo tenta evitar acidentes. Use apenas quando estiver operando em um clone seguro e com plano de comunicação ao time.

Achar que apagar no commit atual resolve

Não resolve. O arquivo ou segredo continua acessível em commits antigos.

Esquecer as tags

Se você só der push forçado nas branches e esquecer as tags, parte do histórico antigo ainda pode permanecer referenciada.

Não orientar o time

Esse é um dos pontos mais negligenciados. Sem alinhar o procedimento pós-rewrite, alguém pode fazer push de uma branch antiga e reintroduzir o problema.

Tratar dotfiles como regra universal

Nem todo arquivo iniciado por . deve ficar fora do versionamento. Isso depende da função do arquivo e da estratégia do repositório.


13. Vídeo complementar

Você também pode complementar a leitura com este vídeo no YouTube, que fala justamente sobre detecção de chaves commitadas e limpeza do histórico:

Learn how to detect committed keys in Git and how to clear the history to solve the problem

https://www.youtube.com/watch?v=HzfK3MZ1UpE


Conclusão

O git-filter-repo é hoje uma das formas mais seguras e práticas de reescrever histórico Git para remover arquivos indevidos e dados sensíveis. Ele é especialmente útil em dois cenários muito comuns:

  • quando um arquivo grande, ZIP ou pasta de build foi versionado por engano;
  • quando uma chave, token ou segredo foi commitado.

O fluxo ideal costuma ser:

  1. identificar o problema;
  2. analisar o histórico;
  3. remover o path ou substituir o texto;
  4. forçar push de branches e tags;
  5. alinhar o time para resetar os clones locais;
  6. adicionar Gitleaks no GitHub Actions para evitar recorrência.

Isso transforma um incidente pontual em uma melhoria real de governança do repositório.

Top comments (0)