Solución de problemas de rendimiento causados por archivos grandes en Git
Diagnostica repositorios Git lentos causados por archivos grandes, elige Git LFS con cuidado y limpia el historial sin sorprender a tu equipo.
Solución de problemas de rendimiento causados por archivos grandes en Git
Los archivos grandes perjudican a Git de una manera que es fácil pasar por alto hasta que el repositorio ya es doloroso de usar. Un solo video, archivo, volcado de base de datos o archivo de diseño puede no parecer peligroso cuando alguien lo agrega. El problema comienza cuando ese archivo cambia varias veces. Git conserva el historial, y cada clon tiene que llevar ese historial.
El síntoma suele ser vago al principio. git clone tarda más de lo que debería. git fetch se siente lento en el Wi-Fi del hotel. Los trabajos de CI pasan demasiado tiempo revisando el repositorio antes de construir. Los desarrolladores comienzan a usar clones locales antiguos porque un clon nuevo es molesto. Ese es el momento de inspeccionar el repositorio en lugar de decirle a todos que tengan paciencia.
Confirma que los archivos grandes son el problema
Comienza con verificaciones simples:
du -sh .git
git count-objects -vH
du -sh .git te dice qué tan pesada es la base de datos del repositorio local. git count-objects -vH muestra objetos sueltos y el tamaño del paquete. Si el tamaño del paquete es grande en comparación con el árbol fuente real, es probable que el historial esté transportando cargas útiles antiguas.
Para encontrar archivos grandes en el checkout actual:
find . -path ./.git -prune -o -type f -size +10M -print
Eso solo muestra lo que existe ahora. Un repositorio puede ser lento debido a un archivo que se eliminó hace meses. Para inspeccionar el historial, Git LFS proporciona un informe útil incluso antes de migrar cualquier cosa:
git lfs migrate info --everything --above=10MB
Si Git LFS no está instalado, aún puedes investigar con los comandos internos de Git, pero el comando anterior suele ser la vista más directa para este problema específico.
Decide qué pertenece a Git
No todos los archivos grandes son un error. Un pequeño conjunto de activos binarios estables puede estar bien. Un repositorio para código de infraestructura no debe contener imágenes de VM, copias de seguridad de bases de datos, exportaciones de clientes o artefactos de compilación. Un repositorio de juegos puede contener legítimamente activos de arte y audio, pero esos archivos generalmente necesitan Git LFS o un sistema de activos separado.
Una regla práctica es esta: Git es excelente para texto fuente y archivos pequeños de soporte. Git es deficiente para blobs binarios que cambian con frecuencia. Si el archivo no puede ser revisado de manera significativa en un diff y cambia a menudo, probablemente no debería vivir como un objeto normal de Git.
Los candidatos comunes para Git LFS incluyen:
*.psd
*.ai
*.mp4
*.mov
*.wav
*.zip
*.uasset
*.fbx
*.blend
Ten cuidado con patrones amplios de imágenes. Rastrear cada *.png en LFS puede ser útil para un repositorio con mucho diseño, pero puede ser molesto para una aplicación web con muchos íconos pequeños. Los patrones deben coincidir con los archivos que realmente causan problemas.
Usa Git LFS para archivos grandes futuros
Git LFS almacena un pequeño archivo puntero en Git y mantiene el contenido grande en el almacenamiento LFS. El historial normal de Git se mantiene más ligero, mientras que los usuarios aún obtienen el archivo real en el árbol de trabajo cuando LFS lo descarga.
Instálalo e inicialízalo:
git lfs install
Rastrea los patrones de archivos que realmente necesitas:
git lfs track "*.psd"
git lfs track "*.mp4"
git add .gitattributes
git commit -m "Rastrear archivos grandes de diseño y video con Git LFS"
El archivo .gitattributes es importante. Confírmalo para que todos usen las mismas reglas de LFS.
Después de eso, agrega archivos normalmente:
git add demo.mp4
git commit -m "Agregar video de demostración del producto"
git push origin main
Un colaborador debe instalar Git LFS antes de trabajar con el repositorio. Si clonan sin soporte de LFS, pueden ver archivos puntero en lugar de activos reales hasta que instalen LFS y ejecuten:
git lfs pull
También verifica la política de almacenamiento y ancho de banda en tu host de Git. Git LFS resuelve la hinchazón de objetos de Git, pero no hace que los activos grandes sean gratuitos para almacenar o transferir.
Migrando el historial existente
Habilitar LFS hoy no corrige automáticamente los commits de ayer. Si se confirmó un archivo de 700 MB y luego se eliminó, aún puede vivir en el historial. Limpiarlo requiere reescribir el historial.
La reescritura del historial cambia los IDs de los commits. Cualquiera con un clon existente debe resincronizar cuidadosamente, y las solicitudes de extracción abiertas pueden necesitar ser rebasadas o recreadas. Haz esto en una ventana de mantenimiento y haz primero una copia de seguridad espejo:
git clone --mirror [email protected]:ORG/REPO.git repo-backup.git
Luego trabaja en un clon nuevo. Asegúrate de que el árbol de trabajo esté limpio:
git status
Inspecciona lo que se migraría:
git lfs migrate info --everything --above=10MB
Migra por patrón cuando sea posible:
git lfs migrate import --everything --include="*.psd,*.mp4,*.zip"
O migra archivos por encima de un umbral si el repositorio tiene muchos archivos grandes desconocidos:
git lfs migrate import --everything --above=10MB
Revisa el resultado antes de enviar:
git log --oneline --decorate -5
git lfs ls-files
git status
git lfs migrate info --everything --above=10MB
Si la migración hizo lo que esperabas, envía las ramas y etiquetas reescritas deliberadamente:
git push --force-with-lease origin main
git push --force-with-lease origin --tags
Para un repositorio con muchas ramas activas, decide qué ramas importan. Puede que no necesites reescribir cada rama abandonada, pero cualquier rama que aún contenga los objetos grandes puede mantener el repositorio remoto pesado.
Después de una reescritura del historial
Diles a los compañeros de equipo exactamente qué cambió. La instrucción más limpia suele ser reclonar. Si las personas tienen trabajo local, deben guardarlo primero:
git status
git branch my-work-before-lfs-migration
git fetch origin
git rebase origin/main
Para clones locales desordenados, reclonar es menos arriesgado que intentar reparar quirúrgicamente el historial antiguo.
El almacenamiento remoto puede no reducirse instantáneamente. Los proveedores de alojamiento mantienen objetos inalcanzables por un tiempo, y algunos requieren soporte o mantenimiento del repositorio antes de que se actualicen los números de almacenamiento. Localmente, puedes podar objetos antiguos después de estar seguro de que la migración es buena:
git reflog expire --expire=now --all
git gc --prune=now --aggressive
No ejecutes comandos de limpieza como sustituto de la revisión. Hacen que los objetos locales antiguos sean más difíciles de recuperar.
Previniendo el mismo problema nuevamente
Agrega una verificación pre-commit o pre-receive si los archivos grandes accidentales siguen apareciendo. Un hook pre-commit local puede advertir a los desarrolladores antes de que confirmen un artefacto grande. Una regla del lado del servidor es más fuerte porque protege el repositorio compartido incluso cuando alguien omite los hooks locales.
Una verificación local simple podría rechazar archivos por encima de un tamaño elegido a menos que ya estén rastreados por LFS. El umbral exacto depende del proyecto. Un sitio de documentación y un proyecto de juego no deben usar el mismo límite.
También corrige la fuente de los archivos. Si CI crea dist/, target/, informes de cobertura, archivos o capturas de pantalla dentro del repositorio, agrega las entradas correctas a .gitignore:
dist/
target/
coverage/
*.log
*.zip
No ignores archivos a ciegas. Asegúrate de que las rutas ignoradas sean salidas generadas, no entradas fuente.
Cuando LFS no es la respuesta
Git LFS no es un almacén de artefactos universal. Los resultados de compilación generalmente pertenecen a un registro de paquetes, almacenamiento de objetos, activos de lanzamiento o almacén de artefactos de CI. Los volcados de bases de datos pertenecen al almacenamiento de copias de seguridad. Los conjuntos de datos grandes pueden necesitar una herramienta de versionado de datos o un flujo de trabajo de almacenamiento separado.
El objetivo no es ocultar cada archivo grande de Git. El objetivo es mantener el repositorio lo suficientemente rápido para que las personas puedan clonar, bifurcar, obtener y revisar sin luchar contra la herramienta.
Una buena limpieza deja tres cosas atrás: reglas claras de .gitattributes para archivos que pertenecen a LFS, reglas de .gitignore para archivos que nunca deben ser confirmados, y una breve nota del equipo explicando cómo los clones existentes deben resincronizarse. Eso es lo que evita que la corrección se convierta en una limpieza única que repitas el próximo trimestre.