git ls-tree para coding agents: tree object, no el disco
Resumen
git ls-tree lista un tree object, no el working tree. Exige tree-ish. Default: un nivel. -r recorre; -d solo trees; -l talla de blobs. 160000 es gitlink. Un agente parsea -z, nombra paths, no usa find ni la REST recursive de GitHub. 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-tree no lista el disco. El man (git-ls-tree(1), Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-ls-tree HTTP 200, last-modified 2026-08-31; last updated in 2.42.0, 2.42.1 → 2.55.0 sin cambios) imprime el contenido de un tree object. El synopsis exige <tree-ish>. Sin él, el binario local imprime usage y sale 129. Un blob no es un tree: verificado 2026-09-04, git ls-tree <blob> → not a tree object, 128. Nombre inválido o repo vacío sin HEAD → Not a valid object name, 128.
El default no recorre. Sin -r ves un nivel: blobs, el tree de cada directorio, gitlinks. -r entra a sub-trees y omite las entradas tree salvo que pases -t. -d muestra solo el tree nombrado, no sus hijos, e implica -t. Eso no es ls-files (index + working tree) ni show (un objeto concreto, a menudo con diff).
GitHub Docs (REST API endpoints for Git trees, HTTP 200 2026-09-04, API version 2026-03-10): un tree crea la jerarquía entre directorios y files en el remoto. Get a tree pide Contents read. No sustituye el clone.
Contrato: tree-ish explícito, -z para parsear, pathspec acotado, cero dump del árbol al LLM.
Un nivel no es el repo entero
Default equivalente, según el man: %(objectmode) %(objecttype) %(objectname)%x09%(path). SHA de 40 hex si no pasas --abbrev. TAB entre el objeto y el path. Compatible con --index-info --stdin de update-index; un agente no encadena eso en autónomo.
Verificado 2026-09-04 en un repo de prueba (Git 2.50.1):
| Pregunta | Comando | Qué imprime |
|---|---|---|
| ¿Qué hay en el tree de HEAD? | git ls-tree HEAD | un nivel: blobs + trees + gitlinks |
| ¿Solo directorios? | git ls-tree -d HEAD | entradas 040000 tree |
| ¿Todo el árbol? | git ls-tree -r HEAD | blobs (y gitlinks); sin las filas tree |
| ¿También los trees al recorre? | git ls-tree -r -t HEAD | trees + blobs |
| ¿Tamaño del blob? | git ls-tree -l HEAD | bytes del blob; - en tree y commit |
-l / --long: talla en bytes, alineada a 7 caracteres. Solo blobs. Tree y gitlink (objecttype commit) llevan -. Verificado: blob hello\n → 6; symlink f.txt (modo 120000) → 5; 040000 tree y 160000 commit → -.
Los <path> del synopsis no son pathnames crudos: son patrones. Sin -r, git ls-tree HEAD sub imprime la entrada tree de sub, no los files de dentro. Con -r, imprime los blobs bajo ese patrón. El orden de argumentos no importa.
El cwd cuenta. El man: el path es relativo al directorio actual. Desde sub/, git ls-tree HEAD lista dir, no sub/dir. --full-name imprime el path desde la raíz. --full-tree ignora el cwd e implica --full-name. Verificado desde sub/: default → dir; --full-name → sub/dir; --full-tree → el tree de HEAD. El man avisa: HEAD:sub + dir desde sub/ pide sub/sub/dir.

Lo que el agente sí / no corre
| Quiero | Comando | Trampa |
|---|---|---|
| ¿Este path está en HEAD? | git ls-tree -z --name-only HEAD -- path | find . / ls -R |
| Lista parseable | git ls-tree -z HEAD -- pathspec | default con espacios y core.quotePath |
| Recursivo acotado | git ls-tree -r -z HEAD -- src/ | -r sin path en un monorepo |
| SHA corto | git ls-tree --abbrev=7 HEAD -- path | recortar 40 hex a ojo |
| ¿Es un tree? | git ls-tree --name-only HEAD -- dir | asumir que el disco = el commit |
Prohibido en autónomo:
find/ls -Rvolcado al LLM. El man compara con/bin/ls -ay luego marca las diferencias: patrones, no pathnames crudos; cwd. El disco incluye untracked, ignored y el scratch del agente. El tree no.- Omitir el tree-ish. Verificado: sin argumentos → usage, 129.
- Tratar un blob como tree. Verificado: not a tree object, 128. Para el contenido del file usa show
HEAD:path. -rsin pathspec en un repo grande. GitHub Docs (Get a tree):recursivetopa en 100.000 entradas o 7 MB; sitruncatedes true, baja tree por tree. El prompt también tiene techo. Nombra el path.--name-onlyjunto a--object-only. Verificado: cannot be used together, 129.--formattampoco va con--long/--name-only/--object-only(can't be combined, 129). Talla =-l. Campos =--formatsolo.- Confundir con ls-files.
ls-filesmezcla index y working tree.ls-treeno ve untracked. Un file sucio en disco no cambia la fila hasta un commit. - Pegar la REST Get a tree con
recursive=false“para no recorre”. GitHub Docs: cualquier valor del query (0,1,"true","false") activa la recursión; omitir el parámetro la evita. Create a tree pide Contents write y no mueve la rama.
Modos verificados (mismo experimento; GitHub Docs lista los mismos para Create a tree): 100644 blob file, 100755 blob ejecutable, 120000 blob symlink, 040000 tree, 160000 commit gitlink. objecttype del gitlink es commit, no tree. No es un directorio.

Receta (60 segundos)
Solo en un worktree propio:
git status -sb
git rev-parse --verify --quiet HEAD
git ls-tree -z --name-only HEAD -- src/lib/posts.ts
git ls-tree -d HEAD -- src
Si el ticket pide “árbol de este directorio”:
git ls-tree -r -t -z HEAD -- src/lib
-z: NUL al final, path sin quoting C. Sin -z, core.quotePath puede entrecomillar. Un parser que parte por espacio sobre un path con espacio se rompe. --object-only imprime solo el SHA (40 hex de default). --name-only / --name-status imprimen solo el path. No los combines.
--abbrev[=<n>]: el prefijo más corto de al menos n hex que sigue siendo único. Verificado: --abbrev y --abbrev=7 acortaron a 7 en un repo chico. No es un permiso para recortar SHA a 7 en un script que luego llama rev-parse.
UI de GitHub vs clone local
Get a tree (GET /repos/{owner}/{repo}/git/trees/{tree_sha}): SHA o ref. Contents read; sin auth en repos públicos. Create a tree acepta modos 100644 / 100755 / 040000 / 160000 / 120000 y no actualiza la rama. Un agente de lectura no llama create.
El file finder de github.com busca en el remoto. ls-tree corre en tu objeto. Fetch atrasado = tree atrasado. El SHA es rev-parse; el blob es show.
Checklist
- Worktree propio.
git status -sb. Tree-ish obligatorio. - Default = un nivel. Recursivo =
-r+ pathspec. Trees al recorre =-t(o-d). - Parsear
-z. Cero--name-only+--object-only. Cero--format+-l. - Cwd:
--full-treesi el listing no debe recortarse al directorio actual. -
160000 commites gitlink, no un folder.120000es symlink. - Disco sucio ≠ tree. Index/untracked → ls-files.
- Cero REST
recursive=false“para no recorre”. Cero Create a tree.
FAQ
¿ls-tree es lo mismo que ls-files? No. ls-files mira index y, con flags, el working tree. ls-tree mira un objeto. Untracked no aparece.
¿Por qué -r no muestra src/ como carpeta? El man: -r entra a sub-trees y, sin -t, no imprime la entrada tree. -t o -d la dejan.
¿Puedo usar HEAD:src como tree-ish? Sí. El man: no lo combines con un path relativo al cwd. Prefiere HEAD -- src y --full-tree si hace falta.
El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. ls-tree no es ls-files: lista un tree object, no el index.
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
