# git-filter-repo: Reescribir el historial de Git sin sufrir

Tabla de contenidos

¿Qué es git-filter-repo?

git-filter-repo es una herramienta de línea de comandos para reescribir el historial de un repositorio Git. Es el reemplazo oficial de git filter-branch, que ya está deprecado y que además era lento, propenso a errores y difícil de usar.

La herramienta es un script de Python creado por Elijah Newren. Procesa el historial en una sola pasada, lo que la hace mucho más rápida que su predecesor. Además, tiene protecciones integradas para evitar que pierdas datos por accidente.

¿Por qué existe?

git filter-branch tenía varios problemas:

  • Lento: Recorría el historial commit por commit, lo que en repos grandes podía tomar horas
  • Frágil: Era fácil equivocarse con la sintaxis del shell y corromper el historial
  • Confuso: La documentación misma de Git recomienda no usarlo

La propia documentación de Git dice textualmente:

git filter-repo is recommended instead of git filter-branch

Cuando Git mismo te dice que no uses su propia herramienta, es buena señal de que la alternativa vale la pena.

Instalación

Terminal window
# pip
pip install git-filter-repo
# Arch Linux
sudo pacman -S git-filter-repo
# Debian/Ubuntu
sudo apt install git-filter-repo
# macOS con Homebrew
brew install git-filter-repo

Requisitos: Python 3.6+ y Git 2.24.0+.

Regla de oro: siempre trabaja sobre un clon fresco

Antes de hacer cualquier cosa con git-filter-repo, cloná el repositorio de nuevo:

Terminal window
git clone https://github.com/tu-usuario/tu-repo.git tu-repo-limpio
cd tu-repo-limpio

git-filter-repo está diseñado para operar sobre clones frescos. Si intentás usarlo en un repo que ya tiene un remote configurado, te va a advertir. Esto es una medida de seguridad: si algo sale mal, tu clon original sigue intacto.

Casos de uso

1. Borrar archivos del historial

El caso más común. Alguien commiteó un archivo que no debería estar ahí: un binario de 200MB, un archivo .env con credenciales, un dataset enorme, etc.

Terminal window
# Borrar un archivo específico de todo el historial
git filter-repo --path archivo-pesado.zip --invert-paths
# Borrar un directorio completo
git filter-repo --path data/datasets/ --invert-paths

El flag --invert-paths invierte la selección: en lugar de “quedarse solo con este path”, lo elimina.

Sin --invert-paths, el comportamiento es al revés: conserva solo lo que especificás y borra todo lo demás. Esto es útil para extraer un subdirectorio en un repo nuevo:

Terminal window
# Quedarse solo con el directorio 'libs/utils' y su historial
git filter-repo --path libs/utils/

2. Cambiar la identidad de autor

Este lo he usado personalmente. Si alguna vez commiteaste con el email equivocado (por ejemplo, firmaste commits de un repo laboral con tu cuenta personal), podés corregirlo.

Primero, creás un archivo de mailmap:

mailmap.txt
# Formato: Nombre Correcto <email@correcto.com> Nombre Anterior <email@anterior.com>
Jamer Rebolledo <jamerrq@trabajo.com> Jamer Rebolledo <jamerrq@gmail.com>

Y luego:

Terminal window
git filter-repo --mailmap mailmap.txt

Esto recorre todo el historial y reemplaza las identidades que coincidan.

3. Borrar datos sensibles de archivos

Si un API key o password quedó embebido en el código fuente y se commiteó:

Terminal window
git filter-repo --replace-text expressions.txt

Donde expressions.txt contiene las expresiones a reemplazar:

expressions.txt
# Formato: texto_a_buscar==>texto_de_reemplazo
mi-api-key-secreta==>API_KEY_REDACTED
password123==>***REMOVED***

4. Mover todo a un subdirectorio

Útil cuando querés integrar un repo como subdirectorio de otro (por ejemplo, convertir un repo standalone en un monorepo):

Terminal window
git filter-repo --to-subdirectory-filter mi-proyecto/

Esto reescribe el historial como si todos los archivos siempre hubieran estado dentro de mi-proyecto/.

Después de reescribir

Una vez que terminás de reescribir el historial, necesitás forzar el push al remote:

Terminal window
# Agregar el remote de nuevo (git-filter-repo lo elimina por seguridad)
git remote add origin https://github.com/tu-usuario/tu-repo.git
# Force push
git push --force --all
git push --force --tags

Opciones útiles

FlagDescripción
--dry-runSimula la operación sin modificar nada
--forcePermite ejecutar en un repo que no es un clon fresco
--analyzeGenera un reporte del repositorio (archivos más grandes, etc.)
--strip-blobs-bigger-than 10MElimina blobs mayores a 10MB

El flag --analyze es particularmente útil como primer paso. Genera un directorio .git/filter-repo/analysis/ con reportes que te muestran qué archivos ocupan más espacio, qué extensiones son las más pesadas, y otra información que te ayuda a decidir qué limpiar.

Terminal window
git filter-repo --analyze
# Revisar el reporte
cat .git/filter-repo/analysis/blob-shas-and-paths.txt | head -20

Conclusión

Si necesitás modificar el historial de un repo Git, git-filter-repo es la herramienta indicada. Es rápida, segura y con una interfaz clara. No hay razón para seguir usando git filter-branch.

Un par de recomendaciones finales:

  • Siempre hacé un clon fresco antes de operar
  • Usá --analyze o --dry-run primero para entender qué va a cambiar
  • Coordiná con tu equipo si el repo es compartido

Referencias

Quickly rewrite git repository history (filter-branch replacement)
11.9K929NOASSERTIONPython
My avatar

¡Gracias por leer!


More Posts