Saltar al contenido
Guía9 min

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 · Reportar un error

Continúa con un curso práctico

git 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

PreguntaComandoQué imprime
¿Qué nombre tiene HEAD?git describetag anotado, o tag-N-gSHA
¿Hay un tag exacto en este commit?git describe --exact-matchel tag, o fatal 128
¿El working tree está sucio?git describe --dirtyigual que HEAD, o sufijo -dirty
Incluir lightweightgit describe --tagsel tag más cercano en refs/tags/
Fallback si no hay tagsgit describe --alwaysSHA 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.

Default usa tags anotados; lightweight exige --tags

Lo que el agente sí / no corre

QuieroComandoTrampa
Nombre de HEADgit describegit tag “para ver la versión”
¿Este commit es un tag?git describe --exact-match -- HEADparsear a ojo el string largo
Versión + suciogit describe --dirty--dirty HEAD
Lightweightgit describe --tags --abbrev=0asumir que default los ve
Sin tags en el repogit describe --alwaysinventar 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. describe no sube assets ni pide write.
  • Crear o mover tags “para que describe funcione”. Eso es tag. Aquí solo lees.
  • --dirty con un commit-ish. Verificado: git describe --dirty HEAD → option '--dirty' and commit-ishes cannot be used together, 128. --dirty / --broken describen el working tree de este checkout.
  • --all como “versión”. El man: cualquier ref en refs/ (branch, remote-tracking, lightweight). Verificado: con rama más cercana que el tag, imprime heads/main, no v1. Eso no es SemVer.
  • --debug volcado al LLM. El man: la estrategia va a stderr; el nombre sigue en stdout. No es API.
  • --contains para “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=0 y 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 de f → 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.

--dirty marca el working tree; no se combina con un commit-ish

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-match si el ticket es “¿este commit es un tag?”. Fatal 128 = no.
  • --dirty sin commit-ish. --broken solo si el ticket admite repo corrupto.
  • Cero --all como versión, cero --debug al 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 gratis

Contenido 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.

Al suscribirte, solicitas avisos editoriales. Consulta la política de privacidad. Puedes pedir la baja en contacto.