Introducción
git clone parece una operación pero en realidad compone varias. Entender los pasos ayuda al solucionar problemas con clones parciales, clones lentos o predeterminados sorprendentes.
La secuencia
- Crear el directorio destino.
- Ejecutar
git initdentro de él. - Añadir
origincomo un remoto con la URL fuente. - Configurar el refspec predeterminado
+refs/heads/*:refs/remotes/origin/*. - Ejecutar
git fetch originpara descargar objetos y refs. - Determinar el branch predeterminado (el
HEADdel remoto). - Crear un branch local que lo rastree.
- Hacer checkout de ese branch al árbol de trabajo.
Viéndolo pasar
GIT_TRACE=1 GIT_TRACE_PACKET=1 git clone https://github.com/example/widget.git 2>&1 | head -50
Verás negociación de capacidades, anuncio de refs, negociación want/have y recepción de pack.
Protocolo de cable
Git moderno soporta el protocolo v2 (git config protocol.version 2 o predeterminado en 2.26+). El servidor anuncia solo las refs solicitadas en lugar de la lista completa de refs, lo que mejora dramáticamente los tiempos de clone para repos con muchas refs.
Variantes
git clone --bare # sin árbol de trabajo
git clone --mirror # bare + todas las refs, configurado para mirroring
git clone --depth 1 # shallow
git clone --filter=blob:none # clon parcial, saltar blobs hasta necesitarlos
git clone --filter=tree:0 # incluso menos datos, trees bajo demanda
git clone --single-branch # historial de un solo branch
git clone --branch v1.2.3 # checkout de un branch/tag específico
git clone --recurse-submodules # clonar submódulos también
git clone --no-checkout # saltar populación del árbol de trabajo
Clones parciales
Los clones parciales (--filter) aplazan la descarga de objetos hasta que se necesiten. Requieren soporte del servidor (la mayoría de hosts modernos lo tienen):
git clone --filter=blob:none https://github.com/example/big.git
cd big
git log --oneline # barato; solo se descargan objetos commit y tree
git show HEAD:src/main.c # esto dispara una descarga de blob
Qué va a dónde
Después de un clone exitoso:
.git/objects/pack/: el archivo pack recibido del servidor..git/refs/remotes/origin/: cada branch del servidor como una ref de seguimiento remoto..git/HEAD: ref simbólica al nuevo branch local..git/config: sección[remote "origin"]con URL y refspec.
Anuncio del lado del servidor
Lo primero que el servidor envía en cualquier clone es el anuncio de refs. Bajo el protocolo v0/v1 esto lista cada ref, incluso si solo quieres una; en repos enormes con millones de refs solo el anuncio podría tomar segundos. El protocolo v2 cambia esto: el cliente envía una solicitud ls-refs especificando patrones, y el servidor solo anuncia refs que coincidan:
git -c protocol.version=2 ls-remote origin 'refs/heads/main'
GIT_TRACE_PACKET=1 git -c protocol.version=2 ls-remote origin 2>&1 | head
Para clones del día a día la aceleración es invisible; para servidores de hosting es dramática.
Errores comunes
Clonar un repo enorme en una red inestable y empezar de cero; git clone en 2.30+ soporta clonado reanudable sobre el protocolo HTTP smart, pero solo si el servidor lo soporta. De lo contrario --depth 1 primero, luego git fetch --unshallow después. Clonar en ~/Dropbox u otra carpeta de sincronización; el cliente de sincronización peleará con Git por el control de .git/index. Clonar un repo con submódulos y olvidar --recurse-submodules, terminando con directorios de submódulos vacíos. Finalmente, clonar por HTTPS sin un asistente de credenciales y que te pidan credenciales en cada fetch; configura uno una vez.