git for-each-ref para coding agents: refs locales, cero update-ref
Resumen
git for-each-ref lista refs del clone con format y count. Default: SHA, tipo y TAB al nombre. Un agente acota patrón, %(refname:short) y --count. Cero --shell eval, cero update-ref y cero REST de escritura. Verificado hoy contra el man de 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 for-each-ref no mueve una rama. El man (git-for-each-ref(1); git-scm.com/docs/git-for-each-ref HTTP 200, last-modified 2026-08-31; last updated in 2.54.0, 2.55.0 sin cambios; pie del man local Git 2.54.0, 2026-04-19; binario Git 2.50.1 / Apple Git-155) itera las refs que matchean un patrón, las ordena y las interpola con %(fieldname). Default de --format: %(objectname) espacio %(objecttype) TAB %(refname). HEAD, index y working tree no cambian.
No es branch (porcelain que también crea o borra) ni ls-remote (habla con un remoto, no con el store local). Tampoco es git update-ref: ese man (git-update-ref(1), HTTP 200 2026-09-04) escribe el OID de una ref y puede reescribir HEAD.
GitHub Docs (REST API endpoints for Git references, HTTP 200 2026-09-04, API version 2026-03-10): List matching references y Get a reference piden Contents read (público sin auth). Create / Update / Delete a reference piden Contents write. Un agente de lectura no escribe refs por REST.
Contrato: patrón acotado, --format corto, --count si hay tope, cero eval, cero escritura.
Lista local, no dump
Verificado 2026-09-04 (Git 2.50.1 / Apple Git-155), default con un commit en main:
<40 hex> commit<TAB>refs/heads/main
El TAB es real. El SHA son 40 hex. Repo vacío (solo git init -b main): stdout vacío, 0. Patrón sin match (refs/tags sin tags): stdout vacío, 0. Eso no es “error”; no hay --exit-code aquí.
| Pregunta | Comando | Qué imprime |
|---|---|---|
| ¿Qué refs hay? | git for-each-ref --count=20 --format='%(refname:short)' refs/heads | nombres cortos, tope 20 |
| ¿HEAD y pseudorefs? | git for-each-ref --include-root-refs --format='%(refname)' | HEAD más refs/… |
| ¿Quién apunta a este commit? | git for-each-ref --points-at HEAD --format='%(refname)' | refs cuyo tip es ese objeto |
| ¿Tips no alcanzables desde HEAD? | git for-each-ref --no-merged HEAD --format='%(refname:short)' refs/heads | ramas divergentes |
| ¿Tag anotado? | git for-each-ref --format='%(objecttype) %(refname)' refs/tags | tag refs/tags/v1 |
--count=<n> corta tras n refs. Verificado: --count=2 con tres heads (aa, main, zz) → aa y main. --count=-1 → invalid --count argument, 129. --count=0 en este binario no corta: listó las tres heads igual que sin la flag (--[no-]count trata 0 como ausente). No uses 0 como “silencio”.
--sort=<key>: default refname. Prefijo - invierte. Varias --sort hacen primaria la última. Verificado: --sort=-committerdate puso main (commit más nuevo) antes que topic.
--merged / --contains / --no-merged / --no-contains en Apple Git-155 exigen el commit. Verificado: git for-each-ref --merged --format='…' → malformed object name --format=…. Pasa HEAD explícito.
--start-after está en el man de git-scm (2.54.0). En 2.50.1 / Apple Git-155: unknown option, 129. Un agente en esta máquina no pagina con esa flag.

Lo que el agente sí / no corre
| Quiero | Comando | Trampa |
|---|---|---|
| Ramas locales | git for-each-ref --format='%(refname:short)' refs/heads | git branch -a al LLM |
| Tags | git for-each-ref --format='%(refname:short)' refs/tags | tag -l con anotación larga |
¿Existe main? | git for-each-ref --format='%(refname)' refs/heads/main | tratar stdout vacío como fallo (sigue 0) |
| SHA de una ref | rev-parse --verify --quiet refs/heads/main | dump de %(objectname) de todas las refs |
Prohibido en autónomo:
- Dump sin patrón ni
--count. El default recorre todas las refs. Un clone conrefs/pull, notes o cientos de heads llena el prompt. --shell/--perl/--python/--tcl. El man: citan el valor para eval en ese lenguaje. Verificado:--shell --format='%(refname)'→'refs/heads/main'. Un agente no evalúa ese scriptlet.git update-ref. El man: con dos args guarda<new-oid>en la ref (y puede ir a HEAD); con tres, solo si el valor actual coincide con<old-oid>;-dborra. Un agente no reescribe refs a mano.- REST Create a reference (
POST …/git/refs). GitHub Docs: Contents write,reffully-qualified (refs/heads/…, si no empieza porrefsy tiene dos slashes se rechaza),shaobligatorio, 201 / 409 / 422. No crea refs en un repo vacío (sin ramas), aunque el SHA exista. - REST Update a reference (
PATCH). Contents write.forcedefault false (fast-forward). 200 / 409 / 422. - REST Delete a reference (
DELETE). Contents write. 204. 422 si intentas borrar la rama default. - Mezclar
--stdincon patrones en argv. El man: los patrones vienen de stdin en vez de la lista de argumentos. --color=alwayshacia el LLM. Color en el format ensucia el parseo.
<pattern>: fnmatch o literal; el literal matchea completo o desde el inicio hasta un slash. --exclude usa las mismas reglas. --stdin: un patrón por línea.
--include-root-refs: añade HEAD y pseudorefs. Verificado: sin la flag, HEAD como patrón no lista nada; con la flag, HEAD aparece. En un init sin commits, también sale vacío.

Receta (60 segundos)
Solo en un worktree propio:
git status -sb
git for-each-ref --count=20 --format='%(refname:short)' refs/heads
git for-each-ref --format='%(objectname:short) %(refname:short)' refs/heads/main
Si el ticket pregunta “¿qué ramas no están en HEAD?”:
git for-each-ref --no-merged HEAD --format='%(refname:short)' refs/heads
Cero --shell. Cero update-ref. Cero REST write. Para el remoto, ls-remote, no este comando.
Checklist
- Worktree propio.
git status -sb. - Patrón
refs/heads/refs/tags/ una ref concreta.--countsi el set puede ser grande. -
--formatcon%(refname:short)o un campo. Default solo si vas a parsear SHA + tipo + TAB + ref. -
--merged/--containscon objeto explícito (HEAD), no colgando la flag. - Cero
--shell/--python. Ceroupdate-ref. Cero Create/Update/Delete a reference. -
--start-afterno existe en Git 2.50.1: 129. No paginar con esa flag aquí.
FAQ
¿for-each-ref cambia HEAD? No. Verificado: git status -sb sigue ## main después de listar. Para mover el árbol usa switch, no este plumbing.
¿Por qué no git branch --format? branch reusa los mismos %(fieldname), pero también crea y borra. Un agente que solo lee refs corre for-each-ref con patrón; no pasa cerca de -D / -M / -f.
¿Puedo usar Get a reference? GitHub Docs: Contents read, 200 / 404 / 409. :ref va como heads/<rama> o tags/<tag>. Para el clone local, for-each-ref sobre refs/heads/<rama> no habla con la red.
El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. for-each-ref no es ls-remote: lee el store local; no lista el remoto.
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.

git show-ref para coding agents: refs locales, no el dump al LLM

git hash-object para coding agents: SHA del contenido, no un commit

git ls-remote para coding agents: refs del remoto, cero fetch
