Introducción
git fetch es la operación de red que descarga nuevos objetos y actualiza las refs de seguimiento remoto. No cambia tus branches ni tu árbol de trabajo, lo que lo hace el comando "¿qué hay nuevo?" más seguro.
La secuencia
- Resolver la URL del remoto.
- Abrir una conexión (HTTPS, SSH o git://).
- Negociar capacidades (versión de protocolo, multi-ack, filtros de clon parcial, etc.).
- El servidor anuncia refs (o, en protocolo v2, solo las que coincidan con los patrones solicitados).
- El cliente reporta lo que ya tiene.
- El servidor envía un archivo pack que contiene los objetos faltantes.
- El cliente escribe el pack en
.git/objects/pack/y lo indexa. - El cliente actualiza las refs de seguimiento remoto (
refs/remotes/origin/*). - Opcionalmente poda refs eliminadas.
Comandos
git fetch
git fetch origin
git fetch --all
git fetch --prune
git fetch origin main:my-main # fetch a una ref local
La sintaxis con dos puntos main:my-main crea o actualiza una ref local directamente; úsala con cuidado.
Inspeccionando lo que se descargó
git fetch origin
cat .git/FETCH_HEAD
git log HEAD..origin/main --oneline
FETCH_HEAD lista cada ref actualizada por el fetch más reciente, en el orden solicitado.
Refspecs
Cada remoto tiene uno o más refspecs de fetch. El predeterminado para origin:
+refs/heads/*:refs/remotes/origin/*
Puedes añadir más, por ejemplo para descargar refs de pull-request desde GitHub:
git config --add remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr/*'
git fetch
git switch -c review/123 origin/pr/123
Podando
Sin prune, los branches eliminados en el servidor permanecen como refs origin/* obsoletas:
git fetch --prune
git config --global fetch.prune true
Tags
Por defecto, fetch descarga tags que apuntan a commits descargados. Fuerza o deshabilita:
git fetch --tags
git fetch --no-tags
Trace y debug
GIT_TRACE=1 GIT_TRACE_PACKET=1 git fetch
GIT_CURL_VERBOSE=1 git fetch # HTTPS
Estos revelan las solicitudes exactas, útil para depurar proxies o auth.
Negociación y haves
El handshake de fetch es un baile de "wants" y "haves". El cliente lista lo que quiere (los SHAs de las puntas de los branches remotos), y ofrece haves (commits locales recientes) para que el servidor pueda calcular un pack mínimo. Git moderno usa el algoritmo de negociación skipping, que converge en O(log n) rondas incluso en historiales largos. Puedes ajustarlo:
git config fetch.negotiationAlgorithm skipping
git config fetch.negotiationAlgorithm consecutive
GIT_TRACE_PACKET=1 git fetch 2>&1 | grep -E 'have|want' | head
Errores comunes
Creer que git fetch cambia tus branches; nunca lo hace. Usa git pull o git merge origin/main para integrar. Saltarse --prune en clones de larga duración y acumular docenas de refs origin/* obsoletas. Configurar mal un refspec a mano y sobrescribir branches locales; verifica con git config -e. Finalmente, hacer fetch desde un clon parcial sin darte cuenta de que algunos objetos requerirán una llamada de red de seguimiento al accederlos; los clones parciales intercambian velocidad inicial por latencia ocasional posterior.