git mv para coding agents: index y disco, no /bin/mv
Resumen
git mv renombra o mueve un path tracked y actualiza el index. El destino no puede existir salvo -f; el directorio padre tiene que existir. Un agente nombra paths, corre -n primero y no usa -f, -k ni /bin/mv. 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 mv no es /bin/mv. El man (git-mv(1), Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-mv HTTP 200, last-modified 2026-08-31) mueve o renombra un file, directorio o symlink. Primera forma: <source> (tiene que existir) → <destination>. Segunda: varios sources → un <destination-directory> que ya existe. El index se actualiza al terminar; el cambio sigue sin commit.
GitHub Docs (Moving a file to a new location, HTTP 200 2026-09-04): en la UI hace falta permiso de escritura; si no lo tienes, GitHub te ofrece fork + PR. En una rama protegida no editas ni subes desde la web. El ejemplo de línea de comandos usa /bin/mv + git add . y deja deleted: + untracked. Contrato de agentes: git mv, paths nombrados, -n primero, cero -f/-k autónomo.
Esta guía no sustituye rm (sacar del index) ni add (copiar working tree → index). El contrato: qué forma corre un agente, qué flags están prohibidas, y por qué mv de disco no es git mv.
Index y disco no son lo mismo
/bin/mv de un tracked deja D old + ?? new. Git no infiere el rename hasta que alguien stagea ambos lados. git mv escribe R old -> new en el index en un paso.
El directorio padre del destino tiene que existir. Verificado 2026-09-04: git mv src/foo.ts src/lib/foo.ts con src/lib ausente → No such file or directory, exit 128. mkdir primero, o mueve a un dir que ya está.
Destino ocupado: el man se niega (destination exists) salvo -f. -k salta el error y sale 0: un untracked, un overwrite, un path que Git no controla. En headless eso esconde el fallo.

Lo que el agente sí / no corre
| Quiero | Comando | Trampa |
|---|---|---|
| Renombrar un path tracked | git mv -- old.ts new.ts | /bin/mv + git add . del ejemplo de GitHub |
| Mover a un dir existente | git mv -- a.ts b.ts dest/ | dest/ no existe |
| Ver qué haría | git mv -n -- old.ts new.ts | -n + -f “por si choca” |
| Sacar el path | rm | git mv a /tmp “para borrar” |
Prohibido en autónomo:
-f/--force. El man: even if the destination exists. Verificado:git mv -f other.ts keep.tspisakeep.ts(saleM keep.ts+D other.ts, no unRlimpio). Un agente no pisa un path tracked para “ganar el rename”.-k. Skip de errores. Verificado:git mv -k z.ts z2.tsconz.tsuntracked → exit 0 y cero movimiento. El ticket parece hecho./bin/mv+git add .. GitHub Docs lo enseña para humanos (imágenes que la UI no mueve). Un agente nombra paths (add); no globa el árbol.- Destino cuyo padre no existe. Crea el dir vacío a propósito, o para: el man no crea padres.
- Mover un untracked. Verificado: not under version control, exit 128. Primero add, o no está en el ticket.
- Submodule
git mvautónomo. El man: con gitfile (≥ 1.7.8) actualiza el gitfile,core.worktreeysubmodule.<name>.pathen.gitmodules(salvo-n). BUG documentado: al cambiar entre commits pre/post-move queda un checkout stale en el path viejo y un dir vacío en el nuevo; hay quegit submodule update. Borrar el dir viejo solo es seguro con gitfile; si no, tiras la historia del submodule. Un agente no mueve submodules. git mvde un glob sin comillas a un dir “porque son muchos”. Segunda forma: todos los sources van dentro del dir destino. Un typo de destino (file en vez de dir) no es un lote.
-v / --verbose imprime Renaming a to b. En headless déjalo: quieres ver la línea.
Receta (60 segundos)
Solo en un worktree propio:
git status -sb
git mv -n -- src/lib/foo.ts src/lib/bar.ts
git mv -- src/lib/foo.ts src/lib/bar.ts
git diff --cached --stat
Varios files a un directorio existente:
mkdir -p src/core
git mv -n -- src/a.ts src/b.ts src/core
git mv -- src/a.ts src/b.ts src/core
Cierre = commit + PR. Cero push a main.

UI de GitHub vs clone local
GitHub Docs: en el filename field, carpeta/ crea un subfolder; ../ sube un nivel. Eso es un commit en GitHub, no en tu worktree. Un agente que “ya lo movió en la UI” deja el clone sucio al revés: el path viejo sigue en disco hasta el próximo fetch/pull.
Si tu rama actual es la default, la misma página pide rama nueva + pull request. Un agente no commitea en main (branch, push, PR).
Algunos files (imágenes) la UI no los mueve: hay que línea de comandos. Eso no autoriza git add .. git mv -- path/old.png path/new.png.
Verificado 2026-09-04 en esta máquina (Git 2.50.1 / Apple Git-155): git mv -n old.ts new.ts imprime Checking rename y no mueve (exit 0). Destino existente sin -f → exit 128. Padre ausente → exit 128. Untracked → exit 128. -k sobre untracked → exit 0 y el file no se mueve.
Checklist
- Worktree propio.
git status -sb. Paths del ticket, no el árbol. -
git mv -n -- <src> <dst>antes del mv real. - Padre del destino existe. Cero
-f, cero-k, cero/bin/mv, cerogit add .. - Untracked → add primero, o no es este comando.
- Submodule → para. No
git mvautónomo. - Index staged → commit + PR.
FAQ
¿mv archivo y luego commit? GitHub Docs stagea con git add . tras el mv de disco. Un agente no usa .. Si el disco ya se movió: git add -- old-path new-path (el add de un delete + untracked puede detectar R). Mejor: no uses /bin/mv.
¿git mv dir/? El man mueve el directorio y sus tracked debajo. Sigue siendo un rename en el index. Nómbralo si todo el dir es el ticket; no “por si acaso”.
¿Case rename (foo.ts → Foo.ts)? En APFS (case-insensitive) git mv lo registra como R. Verificado 2026-09-04: exit 0, R foo.ts -> Foo.ts. Sigue necesitando commit. No uses -f.
¿Puedo cambiar el contenido en el mismo commit? GitHub Docs sí lo permite (mover + editar). El index entonces deja de mostrar un R puro (D + A si el blob cambió). Un agente: un commit de rename, otro de edit, o paths explícitos en el mismo commit si el ticket lo pide. Cero git add ..
El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. git mv no es rm: mueve tracked; no lo saca del árbol.
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.

git describe para coding agents: nombre legible, no un Release

git merge-base para coding agents: ancestro común, no folklore

git check-ignore para coding agents: regla ganadora, no adivinar
