Introducción
La recolección de basura (gc) mantiene tu repositorio compacto y rápido. Git la ejecuta automáticamente cuando se exceden ciertos umbrales. También puedes invocarla manualmente.
Qué hace gc
- Empaqueta objetos sueltos en archivos pack.
- Re-deltifica si se le pide.
- Elimina objetos inalcanzables más viejos que la ventana prune-expire.
- Expira entradas del reflog pasado su TTL.
- Opcionalmente escribe el archivo commit-graph.
git gc
git gc --auto
git gc --aggressive
git gc --prune=now
git count-objects -v
Umbrales de auto-gc
git config gc.auto 6700 # umbral de objetos sueltos
git config gc.autoPackLimit 50 # umbral de número de packs
git config gc.autoDetach true # ejecutar en segundo plano
Auto-gc se dispara después de operaciones que crean nuevos objetos, como commit y fetch. Con autoDetach, se ejecuta en segundo plano y Git regresa inmediatamente.
Expiración del reflog
git config gc.reflogExpire 90.days
git config gc.reflogExpireUnreachable 30.days
git reflog expire --expire=90.days --all
Las entradas alcanzables duran 90 días, las inalcanzables 30 por defecto. Los branches y tags que eliminas dejan rastros en el reflog que sobreviven dentro de esa ventana.
Ventana de prune
git config gc.pruneExpire 2.weeks.ago
Los objetos inalcanzables más viejos que esto son elegibles para eliminación durante gc. --prune=now elimina inmediatamente; útil pero peligroso ya que remueve los márgenes de seguridad.
Agresivo vs normal
git gc # rutina: empaquetar nuevos objetos, podar viejos
git gc --aggressive # reconstruir deltas desde cero
El gc agresivo rara vez vale la pena; es CPU-pesado y la ganancia suele ser pequeña. El gc normal es suficiente para la mayoría de repos.
Mantenimiento
Git moderno (2.29+) tiene un subsistema maintenance que consolida y mejora gc:
git maintenance start
git maintenance run --task gc
git maintenance run --task commit-graph
git maintenance run --task incremental-repack
git maintenance start registra un trabajo en segundo plano (cron, launchd o systemd timer) que periódicamente optimiza el repo.
Operaciones bloqueadas
Si gc se interrumpe, puedes ver un archivo de lock obsoleto:
ls .git/gc.pid
rm .git/gc.pid # solo después de confirmar que no hay gc en ejecución
Lo que gc nunca elimina
Varias clases de objetos están exentas de gc hasta que su referencia expire:
- Objetos alcanzables desde cualquier ref bajo
refs/. - Objetos alcanzables desde el reflog de cualquier ref (hasta la expiración del reflog).
- Objetos bajo
refs/stash(la lista de stashes). - Objetos pinned por mappings de
git replace. - Objetos alcanzables desde HEAD e index de los worktrees.
git fsck --unreachable --no-reflogs
git reflog expire --expire-unreachable=now --all
git gc --prune=now
Esa última secuencia es la receta estándar "realmente eliminar historial inalcanzable"; úsala con cuidado.
Errores comunes
Ejecutar git gc --prune=now justo después de una operación destructiva, eliminando la red de seguridad del reflog. Siempre espera la ventana predeterminada a menos que realmente necesites el espacio. Deshabilitar auto-gc en un repo de movimiento rápido, acumulando millones de objetos sueltos. Ejecutar --aggressive en un horario bajo el supuesto de que "más es mejor"; solo quema CPU. Finalmente, ejecutar gc concurrentemente con git push en un servidor; Git moderno maneja la concurrencia de forma segura, pero los scripts personalizados que pelean por .git/objects pueden corromper. Usa git maintenance en lugar de cron jobs caseros.