git pack-refs para coding agents: packed-refs, no el dump al LLM
Resumen
git pack-refs junta tags y refs quietas en $GIT_DIR/packed-refs para no pagar un inode por ref. Default no toca branches activas. --auto sí; --all solo si el humano lo pide. Cero --no-prune autónomo. Cero editar packed-refs. Cero cat al contexto. Distinto de gc y de maintenance. Git 2.50.1.

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 pack-refs empaqueta heads y tags para un acceso más barato al repositorio. El man (git-pack-refs(1); git-scm.com/docs/git-pack-refs; man local Git 2.50.1, 2025-07-22): Pack heads and tags for efficient repository access. SYNOPSIS: git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>].
Tradicionalmente cada tip vive en un archivo bajo $GIT_DIR/refs. Con cientos o miles de tags eso gasta inodes y duele al lookup. El comando escribe esas refs en un archivo, $GIT_DIR/packed-refs. Si una ref no está en el árbol refs/, Git la busca ahí.
No es gc. gc comprime objetos, expira reflogs y también puede llamar a pack-refs (gc.packRefs, default true). pack-refs solo mueve refs. Tampoco es maintenance: maintenance orquesta tareas; pack-refs es una de ellas (weekly en la estrategia incremental). Y no es show-ref: show-ref lee; pack-refs reescribe el almacenamiento de refs.
Contrato: git pack-refs --auto. Cero --all autónomo. Cero --no-prune. Cero editar packed-refs. Cero cat .git/packed-refs al LLM. Cero mezclarlo con git gc.
La regla de oro: tags quietas, branches sueltas
El default no empaqueta todas las branches. Empaqueta tags y las refs que ya estaban packed, y deja el resto. El man lo dice: las branches se desarrollan; compactar su tip no ayuda al rendimiento diario. Un update posterior de una branch siempre crea un archivo suelto otra vez bajo $GIT_DIR/refs.
La práctica recomendada del man: pack-refs --all una vez en un repo con demasiadas refs, y después git pack-refs (sin --all) de vez en cuando. Tags no se espera que cambien. Las heads activas se desempacan al tocarse; la siguiente corrida sin --all las deja sueltas.
--all sí empaqueta todas las refs, con tres excepciones: hidden, broken y symbolic. Un agente no lo corre en el clone del humano: compacta main, HEAD simbólico no (bien), pero sí todas las heads históricas. Si el humano pide compactar un mirror con 40k tags, --all es el comando; si el agente “limpia” un working tree de feature, no.

Flags (qué sí, qué no)
| Flag | Qué hace | Agente |
|---|---|---|
| (default) | Tags + refs ya packed; prune de sueltas empaquetadas | OK si el humano pide compactar tags |
--auto | Pack según el estado del ref DB; formato files o reftable | Contrato. Puede no-op |
--all | Todas las refs excepto hidden/broken/symbolic | Solo si el humano lo pide. Cero autónomo |
--no-prune | Empaqueta y deja las sueltas | Cero. Duplica refs a propósito |
--include <glob> | Solo esos globs; quita el default de tags | Cero autónomo. --exclude gana si hay overlap |
--exclude <glob> | No empaca esos globs; no desempaqueta packed | Cero autónomo |
--auto no es un alias de --all. En formato files, decide por el ratio de refs sueltas contra el tamaño de packed-refs: cuanto más grande el packed, más sueltas hacen falta para volver a compactar. En reftable, compacta tablas para mantener una secuencia geométrica (N al menos el doble de N+1). El comportamiento “puede cambiar en el futuro”, cita el man. Un agente no asume que --auto reescribió nada: si no hay trabajo, sale.
--include precluye el default de tags. Si el agente pasa --include 'refs/heads/tmp/*' pensando “solo esto”, deja de empacar tags. Con --all, --include es no-op. Symbolic y broken nunca se empacan.
--no-prune deja el archivo suelto y la entrada packed. Git resuelve; el disco no. Un agente no lo usa “por si acaso”.
packed-refs no es un log para el modelo
$GIT_DIR/packed-refs es un archivo de texto con SHA y path. Un dump al contexto es el mismo anti-patrón que volcar show-ref o for-each-ref: miles de tags, SHA de release viejos, y cero señal para la tarea.
Leer una ref: git show-ref --verify --quiet refs/tags/v1.2.3 (exit 0/1) o git for-each-ref --count=20 --format='%(refname)' refs/tags. No cat .git/packed-refs. No ls .git/refs/tags. El man avisa un bug documental viejo: textos que dicen “existe el archivo .git/refs/heads/<branch>” cuando quieren decir “la branch existe”. Packed o suelta, la verdad es la ref, no el inode.
Tampoco edites packed-refs a mano. Un SHA mal pegado o una línea a medias rompe lookup. El porcelain escribe el archivo; el agente no es un editor de refs.
gc.packRefs (man de gc): correr pack-refs deja el repo no clonable por Git anterior a 1.5.1.2 sobre transports tontos (HTTP). Default true. Un agente de 2026 no desactiva eso “por compatibilidad con Git 1.5”. Si el humano tiene un bare servido por dumb HTTP a clientes fósiles, es su problema de ops, no un flag que el agente apague.
Relación con gc y maintenance
git gc sí llama a pack-refs cuando gc.packRefs no es false. Por eso un gc --auto puede compactar tags sin que nadie haya escrito pack-refs. El agente que “solo quería objetos” ya tocó refs. Contrato de gc: --auto, nunca --aggressive / --prune=now / --force. Si el humano no pidió housekeeping, no corras ni gc ni pack-refs.
git maintenance run --auto --quiet puede incluir la tarea pack-refs (weekly en incremental). Ahí el orquestador decide. Un agente no dispara --task=pack-refs a pelo en el clone ajeno, igual que no dispara --task=gc. Distinto de prune: prune borra objetos sueltos, no refs.
HEAD y el working tree no se mueven. pack-refs no es checkout, no es reset, no es un merge. Si después de correrlo git status cambió, no fue este comando: alguien más tocó el árbol.

Checklist del agente
- ¿El humano pidió compactar refs o hay evidencia de miles de tags lentas? Si no, no corras pack-refs.
- Comando:
git pack-refs --auto. Si no-op, reporta “nada que empacar” y para. --allsolo con pedido explícito (mirror, repo de tags, historial de branches muertas).- Nunca
--no-prune, nunca--include/--excludeinventados, nunca editarpacked-refs. - Para listar:
show-ref/for-each-refcon pathspec y--count. Cero dump, cerocat. - No sustituyas maintenance ni gc con pack-refs “porque es más barato”. Empaqueta refs, no objetos.
- Si otro proceso tiene el lock del ref DB, espera o aborta. No
--force(pack-refs ni siquiera lo tiene).
FAQ
¿pack-refs borra branches? No. Mueve el almacenamiento del tip. La ref sigue existiendo. --no-prune deja también el archivo suelto; el default sí quita la suelta después de packed.
¿Puedo empacar solo refs/tags/*? Default ya prioriza tags. --include 'refs/tags/*' funciona, pero apaga el default y no empaca refs packed de otro namespace. No lo uses “por precisión” si no sabes el glob.
¿Y reftable? --auto compacta tablas con regla geométrica. No edites las tablas. No asumas packed-refs en un repo reftable: el archivo puede no existir.
¿Lo corro en CI? En un clone efímero, no. En un mirror persistente con 50k tags, un job semanal git pack-refs --auto (o maintenance) sí. Nunca --all en cada PR.
Si estás armando el flujo de un coding agent, el siguiente paso práctico está en el curso de instalar un agente y en el hub de comparativas.
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.

git update-ref para coding agents: plumbing de refs, no mover HEAD

git repack para coding agents: compactar packs, no housekeeping a pelo

git shortlog para coding agents: recuento por autor, no dump de log
