Guía9 min

git symbolic-ref para coding agents: leer HEAD, no reescribirlo

Resumen

git symbolic-ref lee o escribe una ref simbólica. Un arg: path de HEAD. --quiet sale 1 en detached. Dos args mueven HEAD sin checkout. Un agente no escribe HEAD, no borra, no lee .git/HEAD. Git 2.50.1.

GitHub
HEAD es una ref simbólica que apunta a refs/heads; el working tree no se mueve al leerla

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 symbolic-ref lee, crea, actualiza o borra una ref simbólica. El man (git-symbolic-ref(1); git-scm.com/docs/git-symbolic-ref HTTP 200, last-modified 2026-08-31; pie del man local Git 2.50.1.428.g0e8243, 2025-07-22; binario Git 2.50.1 / Apple Git-155) imprime el path relativo a .git/ cuando recibe un argumento. HEAD, index y working tree no se mueven en ese modo.

Una ref simbólica es un archivo cuyo contenido empieza por ref: refs/. El man: históricamente .git/HEAD era un symlink; ahora es texto. Un agente no lee .git/HEAD ni hace readlink.

Eso no es rev-parse (resolver a SHA) ni show-ref (listar refs). Tampoco es switch: switch actualiza el árbol. Dos argumentos aquí solo reescriben el puntero.

GitHub Docs (REST API endpoints for Git references, HTTP 200 2026-09-04): Get a reference pide Contents read y mira github.com. Create / Update / Delete a reference piden Contents write. Ninguno es el HEAD local.

Contrato: un arg + --quiet, ramificar por 0/1, cero escritura.

Un arg lee; dos args escriben

OUTPUT del man (un arg): el path al que apunta, relativo a .git/. --short recorta refs/heads/main a main. Default --recurse: si la ref apunta a otra simbólica, sigue la cadena. --no-recurse para en un nivel.

PreguntaComandoQué imprime
¿A qué apunta HEAD?git symbolic-ref HEADrefs/heads/main
¿Nombre corto?git symbolic-ref --short HEADmain
¿Detached sin ruido?git symbolic-ref --quiet HEADnada; exit 1
¿Un solo salto?git symbolic-ref --no-recurse HEADla ref inmediata

Verificado 2026-09-04 (Git 2.50.1 / Apple Git-155):

  • Attached: HEADrefs/heads/main, 0. --shortmain, 0. --quiet sigue imprimiendo la ref; el man lo calla solo si no es simbólica.
  • Detached: ref HEAD is not a symbolic ref, 128. Con --quiet: silencio, 1. --short en detached: 128.
  • Ref ordinaria (refs/heads/main): no es simbólica. Sin --quiet: 128. Con --quiet: 1. Missing (refs/heads/ghost, main corto): igual.
  • Sin args: usage, 129.
  • Cadena HEADrefs/heads/aliasrefs/heads/feat: default imprime refs/heads/feat. --no-recurse imprime refs/heads/alias. --short imprime feat.
  • Dos args HEAD refs/heads/feat sin switch: exit 0. status muestra ## feat y el working tree sigue el contenido de la rama anterior (M en el archivo). HEAD y el árbol divergen.
  • Dos args a una rama inexistente (HEAD refs/heads/ghost): 0. Después: No commits yet on ghost; rev-parse HEAD falla. HEAD queda colgando.
  • HEAD not-a-ref: Refusing to point HEAD outside of refs/, 128.
  • --delete HEAD: deleting 'HEAD' is not allowed, 128. --delete de un alias simbólico: 0. --delete --quiet de una ref que no es simbólica: 128 con Cannot delete …, not a symbolic ref--quiet no silencia el delete.
  • -m con un motivo solo al escribir: el reflog de HEAD guarda esa frase. Verificado.

El man: exit 0 si imprimió; 1 si el nombre no es simbólica; 128 otro error. Verificado: el 1 aparece con --quiet. Sin --quiet, “no es simbólica” es 128.

--quiet sale 1 en detached; sin --quiet el mismo caso es 128

Lo que el agente sí / no corre

QuieroComandoTrampa
¿Estoy en una rama?git symbolic-ref --quiet HEADcat .git/HEAD
¿Cuál?git symbolic-ref --short HEADgit branch al LLM
¿SHA de HEAD?rev-parse --verify --quiet HEADsymbolic-ref creyendo que da SHA
Cambiar de ramaswitch a la ramasymbolic-ref HEAD refs/heads/…

Prohibido en autónomo:

  • Dos argumentos. El man: creates or updates. Verificado: mueve HEAD sin actualizar index ni working tree. Un worktree queda a medias. Apuntar a un nombre que no existe deja HEAD inválido (0, no 128).
  • --delete / -d. Borra la simbólica. HEAD está protegido (128); un alias no.
  • -m. Escribe reflog. Solo tiene sentido al crear/actualizar, que el agente no hace.
  • Leer .git/HEAD o readlink. El man: los symlinks están deprecados; el formato es ref: refs/…. Packed o worktree miente si solo abriste el archivo.
  • Tratar el 128 de detached como “no hay repo”. Con --quiet es 1. 128 también sale si el string ni siquiera es una ref.
  • --short para ramificar attached/detached. En detached 128 con fatal. Usa --quiet sin --short para el 0/1.
  • Create / Update / Delete a reference en GitHub. Contents write. symbolic-ref es local.

Receta (60 segundos)

Solo en un worktree propio:

git status -sb
git symbolic-ref --quiet HEAD; echo $?
git symbolic-ref --short HEAD

Si el ticket es “¿en qué rama estoy?”: --quiet (1 = detached) y luego --short si fue 0. No parsees fatal.

Si el ticket es “cámbiame de rama”: switch, no dos args.

Cero escritura. Cero .git/HEAD. Cero REST write.

Dos args reescriben HEAD; el working tree no se actualiza

Local vs switch vs SHA

symbolic-ref HEAD dice a qué ref apunta. rev-parse --abbrev-ref HEAD da un nombre o SHA; en detached no falla igual. status -sb muestra la rama y el sucio; no sustituye el 0/1.

switch mueve HEAD y el árbol. branch crea heads; no es el listado ni el puntero. show-ref --verify --quiet -- refs/heads/main pregunta si esa rama existe, no si HEAD la apunta.

GitHub Get a reference es el remoto. Un agente que quiere “¿este checkout está en main?” corre symbolic-ref; el que quiere “¿está main en origin?” corre ls-remote.

Checklist

  • Worktree propio. git status -sb. Un arg por invocación.
  • Attached vs detached: --quiet HEAD0 / 1.
  • Nombre: --short solo después del 0.
  • Cero dos args. Cero --delete. Cero -m. Cero .git/HEAD.
  • Cambiar de rama = switch. SHA = rev-parse.
  • Cero Create/Update/Delete a reference.

FAQ

¿--quiet oculta la rama? No. Verificado: attached imprime igual. Solo silencia el error cuando no es simbólica (detached, ref ordinaria, missing) y sale 1.

¿Por qué sin --quiet el detached es 128 y el man dice 1? El man: 1 si no es simbólica; 128 otro error. Verificado: el 1 aparece con --quiet. Sin él, Git imprime fatal y sale 128. Un agente siempre pone --quiet si va a ramificar por el código.

¿Puedo crear refs/heads/alias como simbólica? El man lo permite (dos args). Un agente no: for-each-ref y scripts humanos tropiezan con heads que no son commits.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. symbolic-ref no es switch: lee el puntero; no actualiza el árbol.