# 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
# pippip install git-filter-repo
# Arch Linuxsudo pacman -S git-filter-repo
# Debian/Ubuntusudo apt install git-filter-repo
# macOS con Homebrewbrew install git-filter-repoRequisitos: 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:
git clone https://github.com/tu-usuario/tu-repo.git tu-repo-limpiocd tu-repo-limpiogit-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.
# Borrar un archivo específico de todo el historialgit filter-repo --path archivo-pesado.zip --invert-paths
# Borrar un directorio completogit filter-repo --path data/datasets/ --invert-pathsEl 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:
# Quedarse solo con el directorio 'libs/utils' y su historialgit 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:
# Formato: Nombre Correcto <email@correcto.com> Nombre Anterior <email@anterior.com>Jamer Rebolledo <jamerrq@trabajo.com> Jamer Rebolledo <jamerrq@gmail.com>Y luego:
git filter-repo --mailmap mailmap.txtEsto 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ó:
git filter-repo --replace-text expressions.txtDonde expressions.txt contiene las expresiones a reemplazar:
# Formato: texto_a_buscar==>texto_de_reemplazomi-api-key-secreta==>API_KEY_REDACTEDpassword123==>***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):
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:
# 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 pushgit push --force --allgit push --force --tagsOpciones útiles
| Flag | Descripción |
|---|---|
--dry-run | Simula la operación sin modificar nada |
--force | Permite ejecutar en un repo que no es un clon fresco |
--analyze | Genera un reporte del repositorio (archivos más grandes, etc.) |
--strip-blobs-bigger-than 10M | Elimina 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.
git filter-repo --analyze# Revisar el reportecat .git/filter-repo/analysis/blob-shas-and-paths.txt | head -20Conclusió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á
--analyzeo--dry-runprimero para entender qué va a cambiar - Coordiná con tu equipo si el repo es compartido
Referencias
- Repositorio oficial en GitHub
- Documentación de git-filter-branch (con la advertencia)
- Manual de git-filter-repo