Guía9 min

git rm para coding agents: index y disco, no /bin/rm

Resumen

git rm quita paths del index y, salvo --cached, también del working tree. El man exige que coincidan con el tip de la rama y no estén staged, salvo -f. Un agente nombra paths, corre --dry-run primero y no usa -r, -f ni globs sin comillas. Git 2.50.1.

GitHub
Un path sale del index y del working tree; el resto del checkout queda intacto

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 rm no es /bin/rm. El man (git-rm(1), Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-rm HTTP 200, last updated in 2.50.0; 2.50.1 → 2.55.0 sin cambios) quita paths del index, o del index y del working tree. No hay flag para borrar solo el disco y dejar el path en el index: para eso el man manda /bin/rm. El inverso —sacar del index y dejar el archivo— es --cached.

GitHub Docs (Deleting files in a repository, HTTP 200 2026-09-04): en la UI hace falta permiso de escritura; si no lo tienes, GitHub te ofrece fork + PR. Borrar el archivo no lo saca del historial. Si el path tenía un secreto, sigue en Git. Contrato: paths nombrados, -n primero, commit nuevo, cero -f/-r autónomo.

Esta guía no sustituye clean (untracked) ni restore (copiar un path desde una fuente). El contrato: qué forma corre un agente, qué flags están prohibidas, y por qué rm de disco no es git rm.

Index y disco no son lo mismo

Sin --cached, el path tiene que coincidir con el tip de la rama y no tener updates staged. El man: ese check se salta con -f. Con --cached, el staged tiene que coincidir con el tip o con el disco; el working tree no se toca.

git rm solo conoce paths que Git rastrea. Un untracked no entra. Un directorio líder (dir) exige -r explícito para borrar dir/file1, dir/file2 y subdirectorios. El glob cruza fronteras: git rm 'd*' también pega a d2; git rm 'd/*' no.

Sparse-checkout: el man solo quita paths dentro del cone. --sparse actualiza entradas fuera. Un agente no ensancha el cone “para que el rm pase”.

--cached saca el path del index y deja el archivo en disco

Lo que el agente sí / no corre

QuieroComandoTrampa
Quitar un path trackedgit rm -- path/to/file.ts/bin/rm y luego esperar que el commit lo note
Dejar el archivo, sacarlo del indexgit rm --cached -- path--cached sobre un dir sin -r
Ver qué haríagit rm -n -- path-n + -f “porque el check molesta”
Untrackedclean -ngit rm de un path que Git no conoce

Prohibido en autónomo:

  • -f / --force. El man: override the up-to-date check. Si el path no coincide con el tip o hay staged, -f borra igual. Un agente no descarta edits locales para “limpiar”.
  • -r sobre un directorio líder. Recursivo a todos los tracked debajo. Un git rm -r src no es “el file del ticket”.
  • Globs sin comillas. El ejemplo oficial git rm Documentation/\*.txt cita el asterisco para que Git expanda. git rm -f git-*.sh deja que el shell liste; no borra subdir/git-foo.sh. Un glob mal citado se come el vecino.
  • --ignore-unmatch para silenciar un path que no existe. Exit 0 con cero matches esconde un typo. Si el path no está, el agente para.
  • --pathspec-from-file=- leyendo un dump enorme. Pathspecs por stdin no son un “rm masivo” de sesión.
  • --sparse para forzar entradas fuera del cone.
  • git ls-files -z | xargs -0 rm -f del apartado vendor drop del man. Eso vacía el working tree. No es el ticket.
  • git add -A / git commit -a “para que Git note los deletes”. El man los cita como atajo humano. Un agente nombra paths (add) y commitea el index (commit).
  • Submodule git rm autónomo. El man: solo gitfile (≥ 1.7.8) sale del work tree; un .git de submodule se mueve al superproject para no tirar historia. Ignored files are deemed expendable y no bloquean. Checkout local sin commit = git submodule deinit, no git rm.
  • Reescribir historia para “borrar de verdad”. GitHub Docs (Removing sensitive data from a repository, HTTP 200 2026-09-04): el delete de un file no saca el blob de Git. Primero revoca o rota el secreto. La herramienta documentada es git-filter-repo. Un agente no filtra el historial ni hace force-push.

-q / --quiet oculta la línea rm por archivo. En headless quieres verla.

Receta (60 segundos)

Solo en un worktree propio:

git status -sb
git rm -n -- src/lib/foo.ts
git rm -- src/lib/foo.ts
git diff --cached --stat

Si el archivo debe quedar en disco (dejar de trackear un .env que ya está ignorado):

git rm --cached -- .env.local
# el file sigue; el index ya no lo tiene

Si el path ya desapareció del disco (/bin/rm de un humano) y solo falta el index:

git diff --name-only --diff-filter=D
git rm --cached -- path/que/ya/no/está

El man documenta exactamente ese pipeline (git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached). Un agente no encadena xargs; nombra el path que vio.

Cierre = commit + PR. Cero push a main.

-f salta el check de up-to-date; -r vacía un directorio tracked

UI de GitHub vs clone local

GitHub Docs (Deleting files in a repository): puedes borrar un file o un directorio entero desde el repo en la web. Eso crea un commit en GitHub, no en tu worktree. Un agente que “ya lo borró en la UI” deja el clone sucio al revés: el path sigue en disco hasta el próximo fetch/pull.

Si el path tenía datos sensibles, la misma página reenvía a Removing sensitive data from a repository. El dato sigue en history, forks, PRs cacheados y clones ajenos. Rotar primero. git rm del tip no es un purge.

Untracked se borra con clean (-n primero; nunca -fdx). Restore copia un path; no lo saca del index. git rm --cached es el unstage que deja disco.

Verificado 2026-09-04 en esta máquina (Git 2.50.1 / Apple Git-155): git rm -n -- README.md lista el path y no lo borra (exit 0). git rm -n -- no-such-file-xyz falla con did not match any files (exit 128). --ignore-unmatch convertiría eso en 0: por eso está prohibido.

Checklist

  • Worktree propio. git status -sb. Paths del ticket, no el árbol.
  • git rm -n -- <path> antes del rm real.
  • Cero -f, cero -r de directorio, cero glob sin comillas, cero --ignore-unmatch, cero --sparse.
  • --cached solo si el disco debe quedarse.
  • Untracked → clean, no git rm.
  • Secreto filtrado: rotar primero, no git rm + force-push.
  • Index staged → commit + PR.

FAQ

¿rm archivo y luego commit? El man: git commit -a y git add -u notan deletes de tracked. Un agente no usa -a. Si el disco ya no tiene el path: git rm --cached -- path (o git rm -- path si aún está).

¿git rm .? Pathspec . con tracked en la raíz, y -r si apuntas a un dir. No. Nombra el file.

¿--cached deshace un add? Saca el path del index. Si el contenido staged no coincide con tip ni disco, el man se niega (salvo que encaje una de las dos). No es restore --staged: restore copia desde una fuente; rm --cached elimina la entrada.

¿Borra el historial? No. El blob vive en commits viejos. GitHub Docs: hay que sacar el file de la historia del repo; git rm del tip no alcanza.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. git rm no es clean: borra tracked del index, no untracked del disco.