Guía9 min

git maintenance para coding agents: housekeeping programado, no gc a pelo

Resumen

git maintenance run orquesta tareas de object database (commit-graph, prefetch, loose-objects, incremental-repack) sin mover HEAD. --auto --quiet es el contrato. Cero start/register/unregister (tocan config global y el scheduler). Cero --task=gc en el clone del humano. Cero mezclarlo con git gc. Distinto de prune y de count-objects. Git 2.50.1.

GitHub
Scheduler de housekeeping Git: tareas incrementales sobre el object database sin mover HEAD ni el working tree

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

git maintenance corre tareas para optimizar los datos del repositorio: acelera otros comandos Git y reduce el almacenamiento. El man (git-maintenance(1); git-scm.com/docs/git-maintenance; man local Git 2.54.0, 2026-04-19; binario Git 2.50.1 / Apple Git-155): Run tasks to optimize Git repository data, speeding up other Git commands and reducing storage requirements for the repository. SYNOPSIS: git maintenance run [<options>] · git maintenance start [--scheduler=<scheduler>] · git maintenance (stop|register|unregister) [<options>].

Porcelain que escribe (git add, git fetch) no se toma el tiempo de compactar: esa escala con el repo entero. maintenance es el orquestador. Por default, solo maintenance.gc.enabled es true. El resto de tareas se enciende con --task= o con maintenance.<task>.enabled.

No es gc. gc es una tarea cara: repacks all Git objects into a single pack-file y can also be disruptive. El man de maintenance lo dice explícito: no combines git gc con git maintenance run. Si hace falta gc, git maintenance run --task=gc — y un agente no lo corre en el clone del humano.

Tampoco es prune ni count-objects. prune borra sueltos. count-objects mira. maintenance programa y ejecuta housekeeping.

Contrato: git maintenance run --auto --quiet. Cero start / register / unregister / stop. Cero --task=gc autónomo. Cero mezclarlo con git gc. Cero reescribir maintenance.*.

La regla de oro: run, no el scheduler

run ejecuta una o más tareas ahora, en este repo, y toma lock del object database. start y register escriben config global (maintenance.repo en ~/.gitconfig) y instalan un scheduler (crontab / systemd-timer / launchctl / schtasks). Un agente no toca la máquina del humano.

register además pone maintenance.strategy=incremental si no existía y apaga el auto-gc de primer plano con maintenance.auto=false en el repo actual. Ese flag sobrevive a unregister. Un agente que “registra para ayudar” deja el clone sin auto-gc.

start = register + scheduler horario. En macOS usa launchctl (plist en ~/Library/LaunchAgents/org.git-scm.git*), no crontab: crontab no tiene contexto de usuario y los credential helpers fallan. Un agente no crea ni pisa esos plist.

Tareas incrementales sobre packs y commit-graph; HEAD y el working tree no se mueven

Tareas (qué corre, qué no)

El man lista las tareas aceptadas por --task=. Estrategia incremental (la de register): gc deshabilitado; commit-graph y prefetch hourly; loose-objects e incremental-repack daily; pack-refs weekly.

TareaQué haceAgente
commit-graphEscribe commit-graph incremental y verifica. No expira .graph del chain anterior.--task=commit-graph --quiet OK
prefetchgit fetch por remoto hacia refs/prefetch/. No mueve remote-tracking ni tags.OK; no es un fetch del humano
loose-objectsDos pasos: borra sueltos ya empaquetados; packea un lote (loose-, default 50k).--auto sí; no a pelo en clone ajeno
incremental-repackmulti-pack-index expire + repack de packs chicos.--auto
pack-refsJunta refs sueltos en un archivo.--auto / weekly
gcEl gc completo. Caro y disruptivo.Cero autónomo
reflog-expireRecorta reflog. Ver reflog.Cero acortar gracia
rerere-gcgc del rr-cache. Ver rerere.Solo si --auto lo pide
worktree-pruneBorra worktrees stale. Ver worktrees.Cero now sobre worktrees ajenos

El man: it is not advisable to enable both the loose-objects and gc tasks at the same time — gc suelta inalcanzables para que loose-objects los limpie después; juntos se pisan.

--auto (con run): corre solo si hay umbral. maintenance.commit-graph.auto default 100 commits fuera del graph; loose-objects.auto 100 sueltos; incremental-repack.auto 10 packs fuera del midx. Cero --schedule a mano (eso es del cron de start). --quiet no reporta progreso a stderr.

Verificado 2026-09-06 (Git 2.50.1 / Apple Git-155). Repo mínimo, un commit, working tree limpio:

  • git maintenance run --task=commit-graph --quiet: 0. rev-parse HEAD igual. status -sb sin cambios.
  • git maintenance run --auto --quiet: 0. Repo chico: umbrales no se cumplen; no hay trabajo. HEAD igual.
  • git maintenance run --task=prefetch --quiet: 0. Sin remotos: no hay fetch. HEAD igual.
  • git maintenance run --task=pack-refs --quiet: 0.
  • git maintenance run --task=loose-objects --quiet: 0.
  • git maintenance run --task=worktree-prune --quiet: 0.
  • git maintenance run --task=rerere-gc --quiet: 0.
  • --task=foo: 129, error: 'foo' is not a valid task.
  • Fuera de un repo: 128, not a git repository.

Lo que el agente sí / no corre

QuieroComandoTrampa
¿Hay housekeeping pendiente?git maintenance run --auto --quietgit gc a pelo “porque está lento”
Commit-graph al díagit maintenance run --task=commit-graph --quietstart para “dejarlo programado”
Ver presión de sueltosgit count-objects -v--task=gc o git gc --aggressive
¿Sigue vivo un SHA?git cat-file -e <sha>reflog-expire / prune a mano

Prohibido en autónomo:

  • git maintenance start / stop / register / unregister. Tocan ~/.gitconfig (maintenance.repo), launchctl/crontab/schtasks y, en register, maintenance.auto=false del repo. El humano no pidió un daemon.
  • --task=gc en el clone del humano o en main. El man: gc can be expensive for large repositories y disruptive. El contrato de gc sigue: --auto --quiet, cero --aggressive / --prune=now.
  • git gc y git maintenance run en el mismo tick. El man: gc no toma el lock igual que maintenance; pueden corromper el object database. If possible, use git maintenance run --task=gc instead of git gc. Un agente no elige ese “if”.
  • Encender loose-objects y gc a la vez (maintenance.*.enabled). El man lo desaconseja.
  • Reescribir maintenance.strategy, maintenance.<task>.enabled, maintenance.<task>.schedule, maintenance.auto. Son perillas del clone.
  • Confundir prefetch con fetch. prefetch escribe refs/prefetch/; no actualiza origin/* ni tags. Un git pull posterior del humano sigue siendo su fetch.
  • unregister --force para “limpiar” un register que el agente no debería haber hecho.
  • Correr maintenance en el worktree del humano. Solo worktree propio.

Receta (60 segundos)

Solo en un worktree propio, y solo si el disco o count-objects -v lo pide:

git status -sb
git maintenance run --auto --quiet
echo $?
git rev-parse HEAD
  • 0 y HEAD igual: listo. Reporta “maintenance --auto” y para.
  • 128: no hay repo. No reintentes con start.
  • 129: tarea u opción desconocida. No inventes un --task.

Cierre = el exit code. Cero commit. Cero push a main. Cero “ahora lo registro en launchctl”.

start/register instalan scheduler global; el agente solo corre run --auto en su worktree

maintenance vs gc vs prune vs count-objects

gc es el housekeeping monolítico. --auto --quiet; cero --aggressive; cero --prune=now. maintenance lo puede invocar como tarea, pero la estrategia incremental lo apaga a propósito: prefiere commit-graph + loose-objects + incremental-repack, que no borran datos.

prune: -n primero; cero a pelo / --expire=now. No es el orquestador.

count-objects: -v para leer count / size / in-pack. Diagnóstico. Cero repack / prune-packed “porque el número es alto”.

rerere: rerere-gc es una tarea de maintenance (gracia 15/60 días). Un agente no corre git rerere gc a mano para “vaciar el cache”.

Lock: cada git maintenance run toma lock del object database. Dos runs concurrentes en el mismo repo: uno no corre. El man: si el lote horario de varios repos tarda más de una hora, chocan. Un agente no lanza maintenance en background (--detach no aplica aquí; eso es de gc) ni en paralelo sobre el mismo .git.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. maintenance no es gc: es el scheduler de tareas incrementales; el agente solo pulsa run --auto.