git describe para coding agents: nombre legible, no un Release
git describe nombra un commit con el tag anotado más cercano. Default ignora lightweight; --tags los incluye. Sin match exacto imprime tag-N-gSHA. --dirty no admite commit-ish. --exact-match falla si no hay tag en el tip. Un agente no lo usa como GitHub Release ni como git tag. Git 2.50.1.
Por Marco Lee · Reportar un error
Continúa con un curso prácticogit describe no crea un tag ni un GitHub Release. El man (git-describe(1), Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-describe HTTP 200, last-modified 2026-08-31; last updated in 2.55.0, 2026-06-29) busca el tag alcanzable más reciente desde un commit-ish (HEAD si omites el argumento). Si el tag apunta exactamente a ese commit, imprime solo el nombre. Si no, añade cuántos commits hay encima y una abreviatura del objeto: v1.2.3-14-g2414721. Ese string también sirve como nombre de objeto para otros comandos Git.
Default sin --all ni --tags: solo tags anotados. Lightweight no cuentan. GitHub Docs (About releases, HTTP 200 2026-09-04): un Release se basa en un Git tag, pide write para gestionarlo y empaqueta zip/tarball. describe no publica nada.
Esta guía no sustituye tag (crear o listar refs/tags/) ni show (inspeccionar el objeto). El contrato: qué forma corre un agente, qué exit code significa, y por qué el default no ve un tag ligero.
Tres salidas, un commit
| Pregunta | Comando | Qué imprime |
|---|---|---|
| ¿Qué nombre tiene HEAD? | git describe | tag anotado, o tag-N-gSHA |
| ¿Hay un tag exacto en este commit? | git describe --exact-match | el tag, o fatal 128 |
| ¿El working tree está sucio? | git describe --dirty | igual que HEAD, o sufijo -dirty |
| Incluir lightweight | git describe --tags | el tag más cercano en refs/tags/ |
| Fallback si no hay tags | git describe --always | SHA abreviado único |
El man (DESCRIPTION): el número extra es el de commits que mostraría git log <tag>..<commit>. El sufijo es -g + abreviatura del tip (la g es de Git, no un SHA). La longitud escala con el tamaño del repo; default mínimo 7. --abbrev=0 suprime el formato largo y deja solo el tag más cercano.
Exit verificado 2026-09-04 (Git 2.50.1 / Apple Git-155): sin tags → No names found, cannot describe anything., 128. Solo lightweight → No annotated tags can describe '…'. However, there were unannotated tags: try --tags., 128. --tags sobre ese lightweight → el nombre, 0. Objeto inválido → Not a valid object name, 128. Tree → is neither a commit nor blob, 128.

Lo que el agente sí / no corre
| Quiero | Comando | Trampa |
|---|---|---|
| Nombre de HEAD | git describe | git tag “para ver la versión” |
| ¿Este commit es un tag? | git describe --exact-match -- HEAD | parsear a ojo el string largo |
| Versión + sucio | git describe --dirty | --dirty HEAD |
| Lightweight | git describe --tags --abbrev=0 | asumir que default los ve |
| Sin tags en el repo | git describe --always | inventar v0.0.0 |
Prohibido en autónomo:
- Tratar la salida como un GitHub Release. GitHub Docs: el Release es un paquete (notas, binarios, zip/tarball del tag). Hasta 1000 assets; cada file < 2 GiB.
describeno sube assets ni pide write. - Crear o mover tags “para que describe funcione”. Eso es tag. Aquí solo lees.
--dirtycon un commit-ish. Verificado:git describe --dirty HEAD→ option '--dirty' and commit-ishes cannot be used together, 128.--dirty/--brokendescriben el working tree de este checkout.--allcomo “versión”. El man: cualquier ref enrefs/(branch, remote-tracking, lightweight). Verificado: con rama más cercana que el tag, imprimeheads/main, nov1. Eso no es SemVer.--debugvolcado al LLM. El man: la estrategia va a stderr; el nombre sigue en stdout. No es API.--containspara “el tag de este commit”. El man: busca el tag que viene después (implica--tags). Verificado: HEAD sin tag posterior → cannot describe, 128.--exact-match/--candidates=0y tragar el fatal. Verificado: commit con un commit encima del tag → no tag exactly matches, 128.- Describir un tree. El man (BUGS): trees y tags que no apuntan a commits no se describen. Un blob sí:
<commit-ish>:<path>del primer commit en un walk inverso desde HEAD. Verificado: blob def→v1-1-g…:f. Lightweight que apunta al blob se ignora. - Encadenar la salida a commit o a un tag
-f. El string nombra un objeto; no es un permiso.
--broken[=<mark>]: si el repo está corrupto y Git no puede saber si hay cambios locales, el default erra; --broken añade -broken (o el mark). Verificado en un árbol sucio y sano: git describe --broken sigue con -dirty, no inventa -broken.
Receta (60 segundos)
Solo en un worktree propio:
git status -sb
git describe
git describe --dirty
git describe --exact-match; echo $?
Si el humano pide “versión aunque no haya tags anotados”:
git describe --tags --always --dirty
--always (man): SHA abreviado único como fallback. Verificado: repo sin tags → 12f5b02, exit 0. Un agente que loguea “versión” en un clone fresco usa esto; no finge un tag.
--long: siempre tag-N-gSHA, incluso si el commit es el tag (v1.2-0-gdeadbee). Verificado: checkout del tag anotado v1 → git describe --long = v1-0-g12f5b02; --abbrev=0 = v1.
--first-parent: el walk no entra al segundo padre de un merge. Sirve para no casar tags de una rama mergeada. Verificado: merge --no-ff de topic (tag v1.1) sobre main (tag v1) → default v1.1-3-g…; --first-parent → v1-2-g…. Un agente de “versión de main” pasa --first-parent si el ticket lo pide; no lo adivina.

UI de GitHub vs clone local
GitHub Docs (About releases): cualquiera con read ve y compara Releases; write para gestionarlos. La fecha del tag puede diferir de la del Release. git describe corre en tu clone: ve tags que hayas fetcheado, no el paquete de github.com.
--match <glob> (sin el prefijo refs/tags/): solo tags que casan. Con --all, también branches y remotes, sin refs/heads/ ni refs/remotes/. Varios --match se acumulan (OR). --exclude resta. Verificado: --match 'v1*' nombra; --match 'nope*' → No names found, 128.
--candidates=<n>: default 10 tags recientes. 0 = solo exacto (--exact-match). Subirlo retrasa un poco y puede acercar el tag. Un agente one-shot no sube el número “por si acaso”.
SEARCH STRATEGY del man: primero match exacto (anotados ganan a lightweight; fecha más nueva gana). Si no, camina ancestros y elige el tag con menos commits de diferencia (git log tag..input mínimo).
Checklist
- Worktree propio.
git status -sb. Default = HEAD. - Default = anotados. Lightweight →
--tags. Cero tags →--always, no un SemVer inventado. -
--exact-matchsi el ticket es “¿este commit es un tag?”. Fatal 128 = no. -
--dirtysin commit-ish.--brokensolo si el ticket admite repo corrupto. - Cero
--allcomo versión, cero--debugal LLM, cero Release. - Crear el tag es tag. Inspeccionar el objeto es show.
FAQ
¿describe es lo mismo que git tag --list? No. tag lista o crea refs. describe nombra un commit con el tag más cercano. Un listado no te dice cuántos commits hay encima.
¿Por qué no veo v0 lightweight? El man: default solo anotados (-a / -s en tag). --tags abre refs/tags/ entero.
¿Puedo parsear tag-N-gSHA por guiones? El tag mismo puede traer guiones. El man fija el sufijo como -<n>-g<abbrev>. Si necesitas el SHA, log -1 --format=%H, no recortes a ciegas.
El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. describe no es tag: nombra un commit; no mueve refs/tags/.
De la guía a la práctica
Ruta Pi.dev: instala tu agente de coding
Lleva tus convenciones de trabajo a Pi.dev: instalación, instrucciones, sesiones y operación segura.
Ver el curso gratisContenido gratis, sin registro. Los servicios externos pueden tener costos.
Avisos cuando actualicemos cursos y guías
Recibe actualizaciones por correo. Es opcional: puedes seguir leyendo y abrir cualquier curso sin suscribirte.
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.

GitHub Copilot CLI: guía práctica del agente de IA en la terminal

Continue.dev: guía práctica del agente open source en VS Code

Goose: guía práctica del agente open source (CLI, Desktop y MCP)
