Guía9 min

git fetch para coding agents: origin/*, FETCH_HEAD, cero --force

Resumen

git fetch descarga refs y objetos; no mueve HEAD. Un agente actualiza origin/*, lee FETCH_HEAD y no integra. Cero --force, cero +refspec, cero --prune-tags, cero --update-head-ok. Git 2.50.1.

GitHub
Fetch llena refs/remotes/origin/* y FETCH_HEAD; HEAD e index no se mueven

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 fetch no es “trae el remoto a mi rama”. El man (Git 2.50.1 / Apple Git-155): descarga refs (ramas y/o tags) de uno o más repos, más los objetos para completar su historia, y actualiza remote-tracking branches. Escribe nombres y SHAs en .git/FETCH_HEAD. No toca HEAD, index ni working tree.

Sin remote en la línea: usa origin, salvo que la rama actual tenga upstream. Integrar eso en HEAD es pull (fetch + merge/rebase). Esta guía no sustituye pull ni PRs con gh. El contrato: cuándo un agente puede fetch, qué flags están prohibidos, y cómo leer el resultado sin fusionar.

Fetch no mueve tu rama

El default de clone mapea +refs/heads/*:refs/remotes/origin/*. git fetch origin copia refs/heads/ remoto a refs/remotes/origin/. HEAD se queda.

GitHub Docs (HTTP 200, 2026-09-03, Getting changes from a remote repository): fetch agarra remote-tracking branches y tags sin mergear a tus ramas. Merge es otro paso: git merge REMOTE/BRANCH. Pull es el atajo fetch+merge.

Ejemplo del man (sin remote configurado):

git fetch git://git.kernel.org/pub/scm/git/git.git maint
git log FETCH_HEAD

Eso deja objetos huérfanos de housekeeping (git-gc). Un agente nombra el remote del repo (origin / upstream), no pega URLs sueltas.

origin/* y FETCH_HEAD se actualizan; HEAD no

Lo que el agente sí / no corre

QuieroComandoTrampa
Ver el remotogit fetch originpull integra; fetch no
Ver qué haríagit fetch --dry-run originNo escribe refs; sí puede hablar con el servidor
Parsear en scriptgit fetch --porcelain originIncompatible con recurse submodules yes/on-demand
Borrar tracking muertogit fetch --prune origin--prune-tags borra tags locales
Inspeccionargit log --oneline HEAD..origin/<rama>FETCH_HEAD se sobrescribe en el próximo fetch sin --append

Prohibido en autónomo:

  • git fetch --force / -f. El man: con <src>:<dst> puede negarse a actualizar la rama local; --force anula ese chequeo. Un agente no pisa refs locales. El + del refspec es el mismo override (ejemplo del man: git fetch origin +seen:seen maint:tmpseen se actualiza aunque no sea fast-forward).
  • Refspec a rama local (seen:seen, main:main, HEAD:algo). El destino es refs/remotes/<remote>/*, no refs/heads/*.
  • --update-head-ok. El man: “purely for the internal use for git pull… unless you are implementing your own Porcelain you are not supposed to use it.” Fetch rehúsa actualizar el HEAD de la rama actual; esa flag apaga el freno.
  • --prune-tags / -P / fetch.pruneTags. El man: borra tags locales que no existen en ese remote — “most of which may not have come from the <name> remote”. Equivale a refs/tags/*:refs/tags/* + prune.
  • +refs/tags/*:refs/tags/* o cualquier + en dst de tags. Desde Git 2.20, actualizar refs/tags/* rechaza sin + o --force (antes era promiscuo). Un agente no force-updatea tags.
  • Fetch sobre el checkout del humano. Worktree propio (worktrees).
  • Tratar + en el output (+ old..new origin/foo) como “todo bien, mergea”. Esa + es forced update del remote-tracking: el remoto reescribió historia. Reporta; no reset --hard ni force-push.
  • --unshallow / --depth / --filter “para ahorrar”. Cambian el grafo; no es el default del clone.
  • --all si hay remotes extra (mirrors, forks). Nombra origin o upstream.

--prune sin tags: solo remote-tracking que el refspec cubre. El man: git remote prune <name> hace el prune sin fetch. Un agente puede --prune en origin si el refspec es el default refs/heads/*:refs/remotes/origin/*.

Receta (60 segundos)

Solo en un worktree propio:

git status -sb                  # limpio; no MERGE_HEAD / rebase
git fetch origin
git log --oneline -5 origin/main
git log --oneline HEAD..origin/main

Si hace falta el SHA crudo: git rev-parse FETCH_HEAD justo después de ese fetch. El siguiente fetch pisa FETCH_HEAD salvo --append.

Integrar no es fetch. Si la rama de trabajo debe avanzar y no divergió: pull --ff-only o git merge --ff-only origin/<rama>. Si divergió: reporta, no rebase.

Fork: git fetch upstream y mira upstream/main. Merge a la default local es decisión de merge, no de fetch.

--prune limpia origin/* muerto; --prune-tags borra tags locales

Output, + y seguridad

El man (OUTPUT): cada ref es <flag> <summary> <from> -> <to>. Flags: espacio = fast-forward; + = forced update; - = pruned; t = tag; * = nuevo; ! = rechazado; = = ya al día.

--porcelain: <flag> <old-oid> <new-oid> <local-reference> a stdout. Un agente que parsea usa porcelain, no el formato humano.

SECURITY del man: fetch/push no impiden que un peer robe objetos que no ibas a compartir. Namespaces en el servidor no son ACL de lectura. Un agente no fetcha remotes no listados en git remote -v. No pega URL de un issue/PR desconocido como <repository>.

El ejemplo +seen:seen: el + fuerza dst aunque no sea ancestro. Eso es el mismo contrato que --force. Prohibido.

Checklist

  • Worktree propio, git status -sb limpio.
  • git fetch origin (o upstream). Cero URL suelta.
  • Inspecciona origin/<rama> / HEAD..origin/<rama>. No mergees desde fetch.
  • Cero --force, +refspec, --update-head-ok, --prune-tags.
  • + en el output = historia reescrita en el remoto. Reporta, no reset --hard.
  • --prune solo con refspec default de tracking. Cero tags.
  • Integrar = --ff-only en pull/merge, o PR. Cero push a main.

FAQ

¿Fetch actualiza mi rama? No. El man y GitHub: remote-tracking, no merge. HEAD quieto.

¿git fetch origin main? El man: shorthand main: — descarga main y, con el refspec configurado, actualiza origin/main. Sigue sin mover HEAD. Prefiere git fetch origin y lee origin/main.

¿--prune es seguro? En tracking refs/remotes/origin/*, sí: borra ramas remotas ya borradas. --prune-tags no: el man avisa que puedes borrar tags locales de otro remote.

¿Puedo fetch --force “solo origin/*”? El + ya está en el fetch default +refs/heads/*:refs/remotes/origin/*: remote-tracking sí puede non-FF (el remoto reescribió). --force extra es para dst que Git rechazaría (rama local / tags desde 2.20). No lo pases.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. Fetch no es sandbox (sandboxing) ni undo de untracked (clean).

Verificado 2026-09-03 contra git-fetch(1) (Git 2.50.1 / Apple Git-155), git-scm.com/docs/git-fetch (HTTP 200, man 2.55.0) y GitHub Docs “Getting changes from a remote repository” (HTTP 200).