git ls-remote para coding agents: refs del remoto, cero fetch
Resumen
git ls-remote lista refs de un remoto sin bajar objetos. Formato oid TAB ref. --branches y --tags filtran; --refs oculta HEAD y tags pelados. --exit-code sale 2 si no hay match. Un agente nombra origin y un patrón; no dump, no fetch, no REST write. 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 ls-remote no descarga el remoto. El man (git-ls-remote(1), Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-ls-remote HTTP 200, last-modified 2026-08-31; last updated in 2.48.0) lista referencias de un repositorio remoto junto con el commit ID asociado. No toca HEAD, index, working tree ni FETCH_HEAD. Eso no es fetch (trae objetos y actualiza origin/*) ni remote (nombra el set de remotes).
<repository> es una URL o el nombre de un remote (secciones GIT URLS y REMOTES de git-fetch(1)). Sin argumento, usa el remote configurado. Verificado 2026-09-04: repo sin remote → No remote configured to list refs from., 128. Nombre que no es repo → does not appear to be a git repository, 128.
GitHub Docs (REST API endpoints for Git references, HTTP 200 2026-09-04): una ref es un archivo con un SHA. List matching references pide Contents read (público sin auth). Create / Update / Delete a reference piden Contents write. Un agente de lectura no escribe refs por REST.
Contrato: remote explícito, patrón acotado, --exit-code si la pregunta es “¿existe?”, cero dump al LLM.
Lista, no objetos
OUTPUT del man: <oid> TAB <ref> LF. Verificado: SHA de 40 hex y un TAB real, no espacios. Tag anotado, salvo --refs: dos líneas — la ref del tag y la misma con ^{} (el objeto al que apunta). Lightweight no se pela.
| Pregunta | Comando | Qué imprime |
|---|---|---|
| ¿Qué hay en origin? | git ls-remote origin | HEAD, ramas, tags; tag anotado + ^{} |
| ¿Solo ramas? | git ls-remote --branches origin | refs/heads/* |
| ¿Tags sin pelar ni HEAD? | git ls-remote --refs --tags origin | refs/tags/* sin ^{} ni HEAD |
| ¿HEAD apunta a qué rama? | git ls-remote --symref origin HEAD | ref: refs/heads/… TAB HEAD, luego el SHA |
| ¿Existe esta rama? | git ls-remote --exit-code --branches origin main | la fila, 0; sin match, 2 |
--branches / -b y --tags / -t no son excluyentes: juntas muestran refs/heads y refs/tags. El man: --heads y -h son sinónimos deprecados de --branches / -b. Verificado: git ls-remote -h sin más argumentos imprime usage y sale 129 (igual que otros subcomandos). Usa --branches, no -h.
--refs: no muestra tags pelados ni pseudorefs como HEAD. --quiet / -q: no imprime la URL en stderr. Verificado: sin -q, stderr es From <url>; con -q, stderr vacío.
--get-url: expande url.<base>.insteadOf y sale sin hablar con el remoto. Verificado: sin remote origin configurado, git ls-remote --get-url origin imprime el literal origin y sale 0. No es un chequeo de existencia.

Lo que el agente sí / no corre
| Quiero | Comando | Trampa |
|---|---|---|
SHA de origin/main sin fetch | git ls-remote --exit-code --branches origin main | git fetch “para mirar” |
¿Hay tag v1 en el remoto? | git ls-remote --exit-code --refs --tags origin 'v1' | git tag local |
| URL efectiva | git ls-remote --get-url origin | tratar origin impreso como “existe” |
| Parsear | git ls-remote --refs -q origin -- 'refs/heads/main' | partir por espacio; el TAB es el separador |
Prohibido en autónomo:
- Dump sin patrón. El default lista todas las refs (tras
--branches/--tags). Un monorepo con cientos de heads llena el prompt. Nombra el patrón. - Tratar stdout vacío como “no existe”. Sin
--exit-code, el man: sale 0 si habló con el remoto, haya o no match. Verificado: patrónnope*→ stdout vacío, 0. Con--exit-code, el mismo patrón → 2. -hcomo “solo ramas”. Es help.--headstodavía listarefs/heads(verificado) pero el man lo marca deprecado.--upload-pack=<exec>o--server-option. Cambian el binario o el protocolo v2 del otro lado. Un agente no reconfigura el pack del host.--sort=committerdatesobre refs cuyos objetos no están locales. El man: esas keys piden el objeto; si no llegó, error de missing object.version:refname/v:refnamesí ordenan el nombre.- REST Create / Update / Delete a reference. GitHub Docs: Contents write. List sin
:refdevuelve todo el namespace, incluidas notes y stashes si el servidor las tiene. No sustituye el clone ni un patrón dels-remote. - Pegar una URL de issue o PR desconocido como
<repository>. SECURITY de fetch: el peer puede ver objetos que no ibas a compartir. Usa el remote degit remote -v.
<patterns> son globs contra la cola del ref: desde el inicio (refs/heads/foo) o desde un slash (bar matchea refs/heads/bar, no refs/heads/foobar). Verificado 2026-09-04: patrón bar → solo refs/heads/bar; foobar es otra fila.

Receta (60 segundos)
Solo en un worktree propio:
git remote -v
git ls-remote --get-url origin
git ls-remote --exit-code --branches origin main
Si el ticket nombra un tag:
git ls-remote --exit-code --refs --tags origin 'v1.0.0'
--symref (el man: upload-pack hoy solo anuncia el symref de HEAD) confirma a qué rama apunta HEAD en el remoto. No actualiza refs/remotes/origin/HEAD local; eso es fetch.
La UI de GitHub (Viewing branches in your repository, HTTP 200 2026-09-04) parte ramas en Yours / Active (commits en tres meses) / Stale / All. El buscador es substring case-insensitive, sin query extra. Eso no es ls-remote. Checking out pull requests locally recomienda gh pr checkout, no listar refs a mano.
Checklist
- Worktree propio. Remote de
git remote -v, no una URL suelta. - Patrón o
--branches/--tags/--refs. Cero dump del namespace. - “¿Existe?” =
--exit-code. 2 = no hay match. 0 sin esa flag no prueba presencia. - Parsear oid TAB ref. SHA de 40 hex.
--refssi no quieresHEADni^{}. -
-qen scripts (stderr limpio). Cero-h. Cero--upload-pack. - Cero REST write. Cero fetch “para mirar un SHA”.
FAQ
¿ls-remote actualiza origin/main? No. Solo imprime. Para tener el objeto y el remote-tracking usa fetch. ls-remote no deja nada que git show local pueda abrir si ese SHA no estaba ya.
¿Por qué --exit-code y no grep? Sin la flag, cero filas sigue siendo conversación OK (0). Un wrapper que mira solo stdout se cree que el remoto no existe cuando el patrón no matcheó. 2 es el contrato del man.
¿Puedo usar la REST Get a reference? GitHub Docs: :ref va como heads/<rama> o tags/<tag>; si no existe, 404. Prefijo feature sin rama exacta puede devolver featureA / featureB. Para un agente local, ls-remote --exit-code --branches origin feature con glob explícito es más predecible que un prefix HTTP.
El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. ls-remote no es fetch: lista refs; no trae objetos.
Verificado 2026-09-04 contra git-ls-remote(1) (Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-ls-remote HTTP 200, last-modified 2026-08-31, last updated in 2.48.0), git-fetch(1) (HTTP 200), GitHub Docs “REST API endpoints for Git references” y “Viewing branches in your repository” (HTTP 200). En esta máquina: sin remote → 128; --exit-code sin match → 2; sin --exit-code y sin match → 0; -h → usage 129; --get-url origin sin remote → imprime origin y 0; patrón bar no lista foobar; --refs omite HEAD y ^{}; SHA 40 hex; git ls-remote --exit-code https://github.com/git/git.git master → 0 y refs/heads/master.
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 for-each-ref para coding agents: refs locales, cero update-ref

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