Guía9 min

git update-index para coding agents: plumbing del index, no add

Resumen

git update-index registra paths en el index. El contrato autónomo es no usarlo: add para stagear, ls-files para leer bits, sparse-checkout para skip-worktree. Cero assume-unchanged, cacheinfo, --force-remove o --index-info. Distinto de add, ls-files y sparse-checkout. Git 2.50.1, man local verificado.

GitHub
El index de Git como candado: update-index escribe bits que add no debería tocar

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 update-index modifica el index. El man (git-update-index(1); git-scm.com/docs/git-update-index HTTP 200, last-modified 2026-08-31; pie del man local Git 2.50.1.428.g0e8243, 2025-07-22; binario Git 2.50.1 / Apple Git-155): Register file contents in the working tree to the index. SYNOPSIS mezcla --add/--remove, --cacheinfo, --chmod, --assume-unchanged, --skip-worktree, --index-info, --stdin y <file>.... Un solo verbo, demasiados contratos.

El propio man remite a git add: See also git-add(1) for a more user-friendly way to do some of the most common operations on the index. Add es porcelain. update-index es plumbing. El agente autónomo no entra al plumbing.

Contrato: no corras git update-index autónomo. Stagear = git add path. Inspeccionar bits = ls-files -v / -t. Sparse = sparse-checkout, no --skip-worktree a mano. Cero --assume-unchanged para “ignorar” un tracked. Cero --cacheinfo. Cero --index-info. Cero --force-remove. Cero --replace. Cero --chmod headless. Cero --stdin.

Qué hace (y qué no)

Modifies the index. Each file mentioned is updated into the index and any unmerged or needs updating state is cleared. Sin flags extra, lee el working tree y escribe el blob + stat en el index. Default: ignora un path nuevo (--add hace falta) e ignora un path borrado del disco (--remove hace falta). No es un “add silencioso”.

No es add. Add pide paths explícitos, respeta ignore, tiene --dry-run y -p. update-index no confirma y mete un blob ausente (--cacheinfo).

No es ls-files. ls-files lee. -v marca H/S/M para assume-unchanged y skip-worktree. update-index escribe esos bits.

No es sparse-checkout. El man de skip-worktree lo dice en una frase larga y luego se retracta: The update-index flags and the read-tree capabilities relating to the skip-worktree bit predated git-sparse-checkout(1)… we strongly encourage the use of git-sparse-checkout(1) in preference to the low-level update-index and read-tree primitives.

No es gitignore. Ignore cubre untracked. El NOTES del man: Users often try to use the assume-unchanged and skip-worktree bits to tell Git to ignore changes to files that are tracked. This does not work as expected… Git does not provide a way to ignore changes to tracked files.

Tampoco es status. Status consulta el index; update-index lo muta. --refresh a ciegas puede borrar un unmerged.

Diagrama de bits skip-worktree y assume-unchanged en el index

Tabla: flag vs daño autónomo

FlagQué hace el manAgente autónomo
(paths)Actualiza el index desde el working treeNo. Usa add con paths nombrados
--addMete un path que no estabaNo. Add ya lo hace y respeta ignore
--remove / --force-removeSaca el path del index; force aunque el archivo siga en discoNunca. Force-remove implica --remove y deja el archivo huérfano en el árbol
--refresh / --really-refreshRe-mata stat(); really ignora assume-unchangedNo a ciegas. --refresh does not calculate a new sha1
--assume-unchangedPromete que el archivo no cambia; Git omite lstatNunca para “ocultar” un config local
--skip-worktreeSparse: no escribir el archivo; ausencia ≠ deleteNo a mano. Sparse-checkout es el porcelain
--cacheinfo <mode>,<object>,<path>Mete mode+SHA sin el archivo en el discoNunca. Es merge mínimo, no un stage
--index-infoLee stdin en 3 formatos (ls-tree / ls-files --stage)Nunca. Scripts, no un turno de agente
`--chmod=(+-)x`Cambia el bit ejecutable en el index
--replaceBorra la entrada que choca (path vs path/file)Nunca. Pierde el otro lado
--stdin / -zPaths por LF o NULNo. Un path por argv, y ni eso autónomo
--split-index / --untracked-cache / --fsmonitorExtensiones del indexConfig (core.*), no un flag por turno

El man de --cacheinfo: used to register a file that is not in the current working directory. Eso no es “stagear un fix”. Es fingir un checkout. --index-info acepta tres formatos (ls-tree, ls-files --stage, legado); para meter stage 1/2 hay que borrar primero con mode=0. Un agente que pega eso mezcla un conflicto a mano.

assume-unchanged no es .gitignore

Sección USING “ASSUME UNCHANGED” BIT: en filesystems con lstat(2) caro (ejemplo del man: cifs), el bit evita el check. It makes Git to omit any checking and assume it has not changed. Si el archivo cambió, Git puede seguir sin enterarse. git ls-files -v marca esos paths con letra minúscula.

El man advierte el malentendido. assume-unchanged: el archivo sigue en el árbol; Git finge que no cambió. skip-worktree: Git evita escribirlo y trata su ausencia como “no es un delete”. Ninguno ignora un tracked.

NOTES, otra vez: alternate solutions are recommended. Config de ejemplo en el repo + copia a un nombre ignored. No bits mágicos.

Si un merge necesita tocar el path, Git will fail (gracefully). --assume-unchanged en package.json convierte el próximo pull en un conflicto manual.

skip-worktree: usa sparse-checkout

Tell git to avoid writing the file to the working directory when reasonably possible, and treat the file as unchanged when it is not present. Not all git commands will pay attention to this bit.

Comandos como switch/pull/merge evitan escribir esos paths, salvo conflictos. git add -u y commit -a no stagean el delete. Si el archivo aparece en un sparse checkout, Git limpia el bit. Un --skip-worktree suelto no sobrevive.

La guía de sparse-checkout fija cone, set + list, cero --no-cone. update-index no sustituye ese flujo.

Flujo working tree → index: add porcelain vs update-index plumbing

Si el humano insiste

Un solo path, un solo flag, dry-run mental primero. Nunca HEAD. Nunca .. Nunca --stdin.

git ls-files -v -- path/to/file
git status --porcelain=v1 -- path/to/file

--refresh después de un read-tree que el humano pidió, no como “limpia el status”:

git update-index --ignore-missing --refresh

El man: --refresh does not calculate a new sha1 file or bring the index up to date for mode/content changes. Solo re-mata stat. Si el contenido cambió, esto no lo stagea.

--chmod=+x solo si el humano pide el bit ejecutable en el index y core.filemode miente. El man: you may need to use git update-index --chmod=.

--no-assume-unchanged path / --no-skip-worktree path para quitar un bit que alguien dejó. Quitar es más seguro que poner. Confirma con git ls-files -v -- path.

Cero --cacheinfo. Cero --info-only. Cero --unresolve autónomo.

Checklist

  1. ¿El objetivo es stagear un path? → add con el path, no update-index.
  2. ¿Quieres ver bits? → git ls-files -v -- path, no mutar.
  3. ¿Working tree grande? → sparse-checkout, no --skip-worktree suelto.
  4. ¿Un tracked “que no se commitee”? → no hay API. Sample + ignore, no assume-unchanged.
  5. ¿Status raro post-merge? → no --refresh -q --unmerged. Eso traga el error.
  6. ¿Paths por stdin / NUL / cacheinfo? → no. Plumbing de script, no de turno.
  7. ¿--force-remove porque el archivo “sigue ahí”? → no. Eso es borrar del index a propósito.
  8. ¿--replace porque path vs path/file chocan? → no. Pierdes una de las dos entradas.
  9. Extensiones (split-index, untracked cache, fsmonitor) → git config, no un flag por PR.
  10. Después de cualquier excepción humana: git status --porcelain=v1 y git diff --cached --stat.

El curso instalar un agente no cubre el index. Esta guía y add sí.

FAQ

¿Por qué Git se niega a add y el agente piensa en update-index? Porque el path está ignored, es un conflicto o choca path/path/file. update-index --add no arregla ignore; --replace borra el otro lado. Lee status y gitignore.

¿Puedo usar --assume-unchanged en .env.local tracked? No. NOTES: Git no ignora cambios a tracked. El bit se cae en merge. Copia desde un sample ignored.

¿--skip-worktree para no bajar node_modules versionado? No. Eso es sparse-checkout o dejar de trackear el directorio. El bit no es un linter de “archivos pesados”.

¿--cacheinfo para stagear un blob que el agente ya hasheó? No. Salta el working tree. hash-object tampoco escribe el index sin -w, y -w autónomo está vetado.

¿--refresh o --index-version 4? Refresh no recalcula SHA; con --unmerged traga el conflicto. v4 comprime pathnames: no cambies el on-disk format del repo del humano.

Fuentes

  • git-update-index(1), git-scm.com/docs/git-update-index — HTTP 200, last-modified 2026-08-31; man local Git 2.50.1.428.g0e8243 (2025-07-22).
  • git-add(1) — porcelain del index; paths explícitos, no ..
  • git-ls-files(1) -v — lectura de assume-unchanged / skip-worktree.
  • git-sparse-checkout(1) — porcelain que sustituye skip-worktree a mano.