En la lección anterior Ana convirtió su carpeta en un repositorio y creó la primera confirmación del proyecto. Desde entonces ha trabajado unos días más y el historial de gestor-tareas ya tiene varias confirmaciones. Además, el equipo ha publicado el repositorio en un servidor interno para poder compartirlo.
Hoy se incorpora Bruno, que trabaja en macOS. Bruno necesita el proyecto en su portátil, pero no una copia cualquiera: necesita los ficheros y todo el historial, para poder consultar por qué se hizo cada cambio, comparar versiones y, más adelante, aportar las suyas. Descargar un .zip le daría los ficheros de hoy y nada más: cero historial, cero contexto, cero capacidad de colaborar.
La herramienta correcta es git clone. En esta lección veremos qué hace realmente —que es bastante más que copiar ficheros—, qué protocolos existen para acceder a un repositorio remoto y en qué se diferencian, las opciones que más se usan en el día a día (--branch, --depth, --single-branch) y, sobre todo, cuándo se usa clone y cuándo init, que es una duda clásica de quien empieza.
Contenido
- La situación de Bruno
git cloneen su forma más simple- Qué hace realmente
git clone, paso a paso - Protocolos: HTTPS, SSH y ruta local
- Clonar en un directorio con otro nombre
- Clonar una rama concreta con
--branch - Clones superficiales con
--depth --single-branchy otras opciones útilesinitfrente aclone: la diferencia conceptual- Comprobaciones después de clonar
- La situación de Bruno
El repositorio de gestor-tareas está publicado en el servidor interno de la empresa. Bruno tiene tres direcciones posibles para acceder a él:
https://git.ejemplo.es/equipo/gestor-tareas.git (HTTPS) [email protected]:equipo/gestor-tareas.git (SSH) /Volumes/compartido/repos/gestor-tareas.git (ruta local, disco compartido)
Las tres apuntan al mismo repositorio: un repositorio bare —sin directorio de trabajo, como vimos al final de la lección anterior— que actúa como punto central del equipo. Cómo llegó allí el repositorio de Ana y cómo se gestionan estas direcciones es materia del módulo 4; aquí nos centramos en el otro lado de la operación: traérselo.
Bruno ya tiene Git instalado y configurado con su identidad, siguiendo lo que vimos en el módulo 1:
git config --global user.name
# → Bruno Salas
git config --global user.email
# → [email protected]
git clone en su forma más simple
git clone en su forma más simpleBruno se sitúa en la carpeta donde guarda sus proyectos y ejecuta:
Cloning into 'gestor-tareas'... remote: Enumerating objects: 24, done. remote: Counting objects: 100% (24/24), done. remote: Compressing objects: 100% (16/16), done. remote: Total 24 (delta 6), reused 0 (delta 0), pack-reused 0 Receiving objects: 100% (24/24), 4.21 KiB | 4.21 MiB/s, done. Resolving deltas: 100% (6/6), done.
Y ya está: en unos segundos tiene el proyecto completo.
c5d9b1e (HEAD -> main, origin/main, origin/HEAD) Documentar la instalación en el README 4e7f2a9 Añadir borrado de tareas al listado 8b6d3c2 Añadir estilos base del listado 1a4c8d6 Estructura inicial del gestor de tareas
Ahí está el historial completo de Ana, incluido el commit inicial que creamos en la lección anterior y la confirmación recurrente "Añadir borrado de tareas al listado" sobre app.js. Bruno no ha recibido una foto del proyecto: ha recibido el proyecto y su memoria.
Y el directorio de trabajo está limpio desde el primer momento:
Descifrando la salida del clon
Las líneas que aparecen durante la descarga no son ruido; describen lo que hace el servidor:
| Línea | Qué significa |
|---|---|
Enumerating objects |
El servidor calcula qué objetos hay que enviar |
Counting objects |
Los cuenta y prepara el envío |
Compressing objects |
Los comprime en un packfile para enviar menos bytes |
Total 24 (delta 6) |
24 objetos, de los cuales 6 se envían como diferencias respecto a otros |
Receiving objects |
Progreso de la descarga en tu máquina |
Resolving deltas |
Tu Git reconstruye los objetos completos a partir de las diferencias |
Ese (delta 6) conecta con algo que mencionamos en El Modelo de Datos de Git: conceptualmente Git guarda instantáneas, pero para almacenarlas y transmitirlas usa packfiles que sí comprimen unos objetos contra otros. Es una optimización invisible: al terminar Resolving deltas, en el disco de Bruno hay exactamente los mismos objetos que en el de Ana.
- Qué hace realmente
git clone, paso a paso
git clone, paso a pasoUn clon parece un simple "descargar carpeta", pero son cinco operaciones encadenadas. Entenderlas evita muchísimas confusiones posteriores.
graph TD
A["1 · Crear el directorio<br/>gestor-tareas/"] --> B["2 · Crear .git/ dentro<br/>(como un git init)"]
B --> C["3 · Descargar TODOS los objetos<br/>y referencias del origen"]
C --> D["4 · Registrar el origen<br/>como remoto 'origin'"]
D --> E["5 · Crear la rama local 'main'<br/>y volcar sus ficheros al<br/>directorio de trabajo"]
Paso 1: crear el directorio
Si no indicas otra cosa, Git usa el último segmento de la URL sin el sufijo .git. De https://git.ejemplo.es/equipo/gestor-tareas.git sale la carpeta gestor-tareas. Si esa carpeta ya existe y no está vacía, el clon falla:
Es una protección deliberada: git clone nunca sobrescribe trabajo existente.
Paso 2: inicializar el repositorio
Internamente, un clon empieza haciendo el equivalente a git init en el directorio destino. Por eso el resultado tiene exactamente la misma anatomía que estudiamos ayer:
Aparecen algunos elementos que en un git init puro no había —index, logs/, packed-refs, FETCH_HEAD— sencillamente porque aquí sí hay contenido: hay ficheros preparados, hay referencias que empaquetar y ha habido una operación de red.
Paso 3: descargar los objetos
Aquí ocurre lo importante. Git descarga la base de datos de objetos completa: todos los blobs, todos los trees, todos los commits y todas las etiquetas del repositorio de origen, junto con sus referencias.
Esto es lo que hace de Git un sistema distribuido, tal como vimos en ¿Qué es Git?: tras el clon, el portátil de Bruno contiene una copia íntegra y funcional del proyecto. Puede consultar el historial, comparar versiones de hace un año o crear confirmaciones sin conexión a la red. En un sistema centralizado como SVN, casi cualquiera de esas operaciones exigiría hablar con el servidor.
Podemos verificarlo:
Los 24 objetos están ahí, en un packfile (in-pack: 24).
Paso 4: registrar el remoto origin
El clon guarda de dónde vino, con el nombre convencional origin:
origin https://git.ejemplo.es/equipo/gestor-tareas.git (fetch) origin https://git.ejemplo.es/equipo/gestor-tareas.git (push)
Y lo deja escrito en la configuración local del repositorio:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = https://git.ejemplo.es/equipo/gestor-tareas.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/mainorigin no es una palabra reservada de Git: es solo el nombre por defecto que clone le pone al remoto. Podrías llamarlo central, upstream o servidor. La convención está tan asentada que conviene respetarla.
La sección [branch "main"] significa que la rama local main sigue a origin/main. Gracias a eso git status puede decirte si vas por delante o por detrás del servidor. Todo esto —remotos, ramas de seguimiento, fetch, pull, push— es el contenido del módulo 4; aquí basta con saber que el clon lo deja configurado solo.
Paso 5: crear la rama local y volcar los ficheros
Por último, Git crea una rama local que corresponde a la rama por defecto del origen (main), sitúa HEAD en ella y escribe en el disco los ficheros de esa confirmación, poblando a la vez el directorio de trabajo y el área de preparación.
Ese último matiz explica por qué git status sale limpio nada más clonar: las tres zonas —repositorio, área de preparación y directorio de trabajo— están sincronizadas en el mismo contenido.
- Protocolos: HTTPS, SSH y ruta local
La URL que le pasas a git clone determina cómo viajan los datos. Estos son los tres casos que encontrarás en la práctica:
| HTTPS | SSH | Ruta local | |
|---|---|---|---|
| Forma | https://host/grupo/repo.git |
git@host:grupo/repo.git |
/ruta/al/repo.git o file:///ruta |
| Autenticación | Usuario + token de acceso | Par de claves pública/privada | Permisos del sistema de ficheros |
| Puerto habitual | 443 | 22 | — |
| Atraviesa cortafuegos | Casi siempre | A veces bloqueado | — |
| Pide credenciales al clonar | Sí, salvo repositorio público | No, si la clave está cargada | No |
| Comodidad diaria | Media (necesita gestor de credenciales) | Alta, una vez configurada | Máxima |
| Uso típico | Primer contacto, CI, redes restrictivas | Trabajo diario de un desarrollador | Copias de seguridad, pruebas, discos compartidos |
HTTPS
Es la opción más universal porque el puerto 443 está abierto prácticamente en todas partes. Al clonar un repositorio privado te pedirá credenciales:
Cloning into 'gestor-tareas'... Username for 'https://git.ejemplo.es': bruno.salas Password for 'https://[email protected]':
Un aviso importante: en las plataformas modernas (GitHub, GitLab…) esa "contraseña" no es la contraseña de tu cuenta, sino un token de acceso personal. Para no reintroducirlo cada vez, sirve el credential.helper que configuramos en Configuración Inicial.
SSH
Fíjate en que la forma SSH abreviada no lleva :// y usa dos puntos para separar el host de la ruta:
git clone [email protected]:equipo/gestor-tareas.gitSe apoya en un par de claves criptográficas: la pública se registra en el servidor y la privada se queda en tu máquina. Una vez configurado, clonar y trabajar no vuelve a pedir contraseña. Es la opción preferida para el trabajo diario. La generación de claves y su registro se explican en Autenticación con Repositorios Remotos.
Existe también la forma larga equivalente, que sí lleva :// y permite especificar puerto:
git clone ssh://[email protected]:2222/equipo/gestor-tareas.gitRuta local
Puedes clonar de una carpeta del propio disco o de un recurso montado en red:
git clone /Volumes/compartido/repos/gestor-tareas.git
git clone ~/copias/gestor-tareas.git copia-de-trabajoEs rapidísimo y no necesita ni red ni credenciales. Tiene una peculiaridad útil: cuando origen y destino están en el mismo sistema de ficheros, Git usa enlaces duros para los objetos en lugar de copiarlos, así que el clon ocupa casi nada. Si prefieres una copia realmente independiente:
Y si escribes la ruta con el prefijo file://, Git usa el mismo mecanismo de transferencia que emplearía con un servidor remoto, lo que resulta práctico para hacer pruebas:
Cuidado con clonar de un repositorio no bare. Se puede clonar de un repositorio normal (por ejemplo, directamente de
~/proyectos/gestor-tareasde Ana), y funciona: obtienes todo el historial. Pero solo obtienes lo confirmado: los cambios que Ana tenga sin confirmar en su directorio de trabajo o en su área de preparación no viajan. Es una fuente de sorpresas: "he clonado tu repo y falta tu último cambio" casi siempre significa "no lo habías confirmado".
- Clonar en un directorio con otro nombre
Basta con añadir el nombre deseado como segundo argumento:
El repositorio es idéntico; solo cambia la carpeta que lo contiene. Es útil en tres situaciones:
- Evitar colisiones: ya tienes una carpeta
gestor-tareasde otro proyecto. - Tener dos copias del mismo repositorio, por ejemplo una para trabajar y otra para consultar una versión antigua sin tocar la primera. (Para este caso concreto existe una herramienta específica, git worktree, que verás en el módulo 6.)
- Nombres poco descriptivos: si el repositorio se llama
web, quizá prefierasweb-cliente-acme.
Si quieres clonar en el directorio actual y no en uno nuevo, usa . como destino. El directorio debe estar vacío:
- Clonar una rama concreta con
--branch
--branchPor defecto, el clon te deja situado en la rama por defecto del origen (main). Con --branch (o -b) eliges otra:
Dos precisiones importantes:
- Se descarga todo el repositorio igualmente.
--branchno filtra lo que llega; solo decide en qué rama te deja. Las demás siguen ahí, accesibles. - También acepta etiquetas. Si le pasas un nombre de etiqueta, obtendrás el contenido exacto de esa versión, pero en estado detached HEAD (no estarás en ninguna rama):
Es perfectamente válido para inspeccionar una versión publicada. Qué significa exactamente ese estado y cómo salir de él corresponde a Entendiendo las Ramas y a Etiquetando Confirmaciones.
- Clones superficiales con
--depth
--depthEn un proyecto con años de historia, clonarlo entero puede significar descargar cientos de megabytes que quizá no necesites. --depth limita cuántas confirmaciones se traen:
Cloning into 'gestor-tareas'... remote: Enumerating objects: 6, done. remote: Total 6 (delta 0), reused 0 (delta 0) Receiving objects: 100% (6/6), 1.83 KiB | 1.83 MiB/s, done.
Compara con el clon completo del apartado 2: 6 objetos en lugar de 24. Solo ha llegado la última confirmación.
La palabra grafted ("injertado") marca el punto donde el historial se corta artificialmente. Ese commit parece no tener padre, aunque en el repositorio original sí lo tenga.
Qué se pierde con un clon superficial
| Operación | Clon completo | --depth 1 |
|---|---|---|
| Ver los ficheros actuales | Sí | Sí |
| Compilar / ejecutar el proyecto | Sí | Sí |
| Crear confirmaciones nuevas | Sí | Sí |
git log completo |
Sí | No, solo la última |
git blame fiable |
Sí | No |
git bisect para buscar un fallo |
Sí | No |
| Comparar con versiones antiguas | Sí | No |
| Tamaño de descarga | 100 % | Mínimo |
Cuándo usarlo y cuándo no
Sí:
- Integración continua. Un servidor de CI compila y descarta la copia; el historial le sobra. Es, con diferencia, el uso más común.
- Contenedores e imágenes de despliegue, donde cada megabyte cuenta.
- Consulta puntual de un proyecto enorme del que solo quieres ver el código de hoy.
No:
- Tu copia de trabajo diaria. Te quedas sin
blame, sinbisecty sin poder comparar con el pasado, que son tres de las razones para usar Git.
Convertir un clon superficial en completo
Si te arrepientes, no hace falta volver a clonar:
O traerte más profundidad de la que tienes:
Ambos comandos pertenecen al módulo 4; los mencionamos aquí para que sepas que la decisión es reversible.
Nota moderna. En Git reciente existen los clones parciales (
--filter=blob:none), que descargan todo el grafo de commits pero traen el contenido de los ficheros solo cuando hace falta. Conservanlog,blameybisecty suelen ser mejor opción que--depthpara repositorios grandes. Lo veremos en Escalando Git para Proyectos Grandes.
--single-branch y otras opciones útiles
--single-branch y otras opciones útiles--single-branch descarga únicamente la rama indicada, ignorando las demás:
A diferencia de --depth, conserva todo el historial de esa rama; lo que evita es traer ramas que no te interesan. En un repositorio con doscientas ramas de trabajo, la diferencia se nota.
Nota importante: --depth implica --single-branch automáticamente, salvo que añadas --no-single-branch.
Un resumen de las opciones más frecuentes:
| Opción | Efecto | Uso típico |
|---|---|---|
-b, --branch <nombre> |
Sitúa en esa rama o etiqueta | Trabajar en desarrollo desde el minuto uno |
--depth <n> |
Solo las n últimas confirmaciones |
Integración continua |
--single-branch |
Solo una rama, con todo su historial | Repositorios con muchas ramas |
--no-checkout, -n |
Descarga pero no vuelca los ficheros | Preparar el repositorio antes de poblarlo |
--bare |
Clon sin directorio de trabajo | Crear una réplica para servir |
--mirror |
Como --bare, pero réplica exacta de todas las referencias |
Copias de seguridad, migraciones |
--recurse-submodules |
Clona también los submódulos | Proyectos con submódulos |
--origin <nombre>, -o |
Llama al remoto de otra forma | Cuando origin ya significa otra cosa |
--quiet, -q |
Sin barras de progreso | Scripts |
Un par de ejemplos comentados:
# Copia de seguridad completa del repositorio del equipo
git clone --mirror https://git.ejemplo.es/equipo/gestor-tareas.git copia-gestor.gitEsto crea un repositorio bare con todas las referencias del origen, no solo las ramas. Es la forma habitual de migrar un repositorio de un servidor a otro.
# Clonar llamando al remoto "central" en lugar de "origin"
git clone --origin central https://git.ejemplo.es/equipo/gestor-tareas.git
git remote -v
# → central https://git.ejemplo.es/equipo/gestor-tareas.git (fetch)
# → central https://git.ejemplo.es/equipo/gestor-tareas.git (push)
init frente a clone: la diferencia conceptual
init frente a clone: la diferencia conceptualEs la duda más habitual al empezar, y se resuelve con una pregunta: ¿ya existe el proyecto en algún sitio?
git init |
git clone |
|
|---|---|---|
| Punto de partida | Nada o una carpeta con ficheros tuyos | Un repositorio que ya existe |
| Historial resultante | Vacío: cero confirmaciones | Completo, idéntico al del origen |
| Remoto configurado | Ninguno | origin, automáticamente |
| Rama inicial | La de init.defaultBranch, sin existir aún |
La rama por defecto del origen, ya creada |
| Directorio de trabajo | Lo que ya tuvieras | Poblado con los ficheros del origen |
| Necesita red | No | Sí (salvo ruta local) |
| Frase que lo resume | "Empiezo un proyecto" | "Me uno a un proyecto" |
Ana usó init porque el proyecto nacía con ella. Bruno usa clone porque el proyecto ya existía. Cada persona del equipo hará clone una vez por proyecto y por máquina; init se ejecuta una sola vez en la vida de un proyecto.
graph TD
Q{"¿El proyecto ya existe<br/>en un repositorio Git?"}
Q -->|No| I["git init<br/>Historial vacío<br/>Sin remoto"]
Q -->|Sí| C["git clone URL<br/>Historial completo<br/>Remoto 'origin' listo"]
I --> P["Primer commit"]
C --> W["Empezar a trabajar<br/>directamente"]
Un error frecuente merece mención aparte: hacer git init en una carpeta vacía con la intención de "bajarse" un proyecto que ya existe, y después intentar conectarlo a mano. Es posible —añadiendo el remoto y descargando, como veremos en el módulo 4— pero es dar tres pasos donde git clone da uno, y es fácil dejarlo mal configurado. Si el proyecto ya existe, clona.
- Comprobaciones después de clonar
Estas cuatro comprobaciones toman diez segundos y evitan malentendidos:
# 1. ¿De dónde vino este repositorio?
git remote -v
# → origin https://git.ejemplo.es/equipo/gestor-tareas.git (fetch)
# → origin https://git.ejemplo.es/equipo/gestor-tareas.git (push)
# 2. ¿En qué rama estoy?
git branch --show-current
# → main
# 3. ¿Tengo el historial completo o es un clon superficial?
git rev-parse --is-shallow-repository
# → false
# 4. ¿Cuántas confirmaciones he recibido?
git rev-list --count HEAD
# → 4Y una quinta que es la más importante en un equipo con perfiles condicionales (includeIf), como el que montamos en Configurando Git:
git config user.email
# → [email protected]Comprobarlo antes de la primera confirmación es mucho más barato que corregir la autoría después, que exige reescribir el historial.
Errores Comunes y Consejos
- Clonar dentro de un repositorio existente. Si ejecutas
git clonesin fijarte y estás dentro de otro proyecto, acabas con un repositorio anidado que confunde a Git y a tus compañeros. Comprueba conpwdantes, o congit rev-parse --show-toplevel. - Usar
--depth 1en la copia de trabajo diaria. Ahorras unos segundos una vez y pierdesblame,bisecty todas las comparaciones históricas durante meses. Resérvalo para CI y contenedores. - Confundir la URL SSH con la HTTPS.
git@host:grupo/repo.gites SSH (sin://, con dos puntos);https://host/grupo/repo.gites HTTPS. Si copias la de SSH sin tener claves configuradas, el clon fallará conPermission denied (publickey). - Creer que clonar copia también el trabajo sin confirmar. El clon trae solo lo confirmado. Si falta algo, casi siempre es porque no se confirmó.
- Esperar que el
.gitignorehaga desaparecer ficheros al clonar. El clon reproduce lo que hay en el historial. Si un fichero indeseado se confirmó en su día, llegará igualmente; ignorarlo ahora no lo saca del pasado. - Clonar un proyecto enorme por HTTPS en una red lenta y darlo por colgado. Usa
git clone --progresso añade--depthsi de verdad no necesitas el historial. - Consejo: si el clon falla a mitad, borra la carpeta a medio crear antes de reintentar; si no, el segundo intento fallará con
destination path already exists. - Consejo: justo después de clonar, ejecuta
git log --oneline -5y échale un vistazo al README. Son dos minutos que te ahorran preguntas al equipo.
Ejercicios
Ejercicio 1: Simular el clon de Bruno con una ruta local
Sin servidor ni red, reproduce el escenario completo. Partiendo de un repositorio con dos confirmaciones que simule el de Ana:
- Crea
~/practica/ana/gestor-tareascon unREADME.mdy unapp.js, e inicialízalo con dos confirmaciones. - Crea a partir de él un repositorio bare en
~/practica/servidor/gestor-tareas.gitque haga de punto central. - Clónalo en
~/practica/bruno/gestor-tareas, simulando a Bruno. - Demuestra con comandos que Bruno tiene: las dos confirmaciones, el remoto
originapuntando al bare, y la ramamainsiguiendo aorigin/main.
Ejercicio 2: Comparar un clon completo con uno superficial
Usando el repositorio bare del ejercicio anterior (amplíalo antes a cinco confirmaciones para que se note la diferencia), haz dos clones: uno completo y otro con --depth 1. Después:
- Compara el número de objetos de cada uno.
- Compara la salida de
git log --oneline. - Intenta ejecutar
git logsobre un fichero concreto en ambos y explica la diferencia. - Convierte el clon superficial en completo y comprueba que ahora se comporta igual que el otro.
Ejercicio 3: Elegir la orden correcta
Para cada situación, indica qué comando exacto usarías y justifica brevemente por qué. Hay una trampa deliberada en la lista.
- Carla empieza hoy y necesita
gestor-tareasen su Windows 11, con todo el historial, para trabajar a diario. - El servidor de integración continua debe compilar la última versión de
mainen cada cambio, lo más rápido posible. - Ana quiere empezar un proyecto nuevo,
informes-mensuales, que todavía no existe en ninguna parte. - Bruno necesita revisar cómo era
estilos.cssen la versión etiquetadav1.0, sin dejar de trabajar en su copia actual. - El equipo migra de servidor y hay que llevarse el repositorio íntegro, con todas las ramas y etiquetas.
- Carla ya tiene la carpeta
gestor-tareascon el proyecto descargado en.zipde un compañero y quiere "conectarla" al repositorio del equipo.
Soluciones
Solución al Ejercicio 1
Paso 1 — el repositorio de Ana:
mkdir -p ~/practica/ana/gestor-tareas
cd ~/practica/ana/gestor-tareas
git init
echo "# Gestor de Tareas" > README.md
git add README.md
git commit -m "Estructura inicial del gestor de tareas"
echo "const tareas = [];" > app.js
git add app.js
git commit -m "Añadir el esqueleto de la lógica de tareas"
git log --oneline7d2f9a1 (HEAD -> main) Añadir el esqueleto de la lógica de tareas 1a4c8d6 Estructura inicial del gestor de tareas
Paso 2 — el repositorio central bare:
mkdir -p ~/practica/servidor
cd ~/practica/servidor
git clone --bare ~/practica/ana/gestor-tareas gestor-tareas.git--bare crea la réplica sin directorio de trabajo, que es exactamente lo que debe ser un repositorio central:
Paso 3 — el clon de Bruno:
mkdir -p ~/practica/bruno
cd ~/practica/bruno
git clone ~/practica/servidor/gestor-tareas.git
cd gestor-tareasPaso 4 — las tres demostraciones:
# Las dos confirmaciones, con los mismos hashes que en el repo de Ana
git log --oneline
# → 7d2f9a1 (HEAD -> main, origin/main, origin/HEAD) Añadir el esqueleto de la lógica de tareas
# → 1a4c8d6 Estructura inicial del gestor de tareas
# El remoto origin apunta al bare
git remote -v
# → origin /home/ana/practica/servidor/gestor-tareas.git (fetch)
# → origin /home/ana/practica/servidor/gestor-tareas.git (push)
# La rama main sigue a origin/main
git status -sb
# → ## main...origin/main
git config branch.main.remote # → origin
git config branch.main.merge # → refs/heads/mainQue los hashes coincidan exactamente con los del repositorio de Ana no es casualidad: como vimos en El Modelo de Datos de Git, el hash se deriva del contenido, así que copiar objetos entre repositorios preserva los identificadores. Esa es la base de que Git pueda sincronizar máquinas distintas sin ambigüedad.
Solución al Ejercicio 2
Ampliamos primero el historial de Ana y lo llevamos al bare (la mecánica de enviar cambios es del módulo 4, así que aquí lo resolvemos volviendo a clonar):
cd ~/practica/ana/gestor-tareas
for n in 3 4 5; do echo "linea $n" >> app.js; git commit -am "Cambio número $n"; done
rm -rf ~/practica/servidor/gestor-tareas.git
git clone --bare . ~/practica/servidor/gestor-tareas.gitLos dos clones:
cd ~/practica
git clone ~/practica/servidor/gestor-tareas.git completo
git clone --depth 1 file://$HOME/practica/servidor/gestor-tareas.git superficial(Se usa file:// porque --depth no tiene efecto sobre una ruta local directa: Git optimiza ese caso copiando o enlazando los objetos enteros.)
1. Número de objetos:
git -C completo count-objects -v | grep in-pack
# → in-pack: 17
git -C superficial count-objects -v | grep in-pack
# → in-pack: 42. El historial:
git -C completo log --oneline
# → e9a2c5f (HEAD -> main, origin/main, origin/HEAD) Cambio número 5
# → b3d7f1c Cambio número 4
# → 5a8e2b9 Cambio número 3
# → 7d2f9a1 Añadir el esqueleto de la lógica de tareas
# → 1a4c8d6 Estructura inicial del gestor de tareas
git -C superficial log --oneline
# → e9a2c5f (grafted, HEAD -> main, origin/main) Cambio número 53. Historial de un fichero:
git -C completo log --oneline -- app.js
# → e9a2c5f Cambio número 5
# → b3d7f1c Cambio número 4
# → 5a8e2b9 Cambio número 3
# → 7d2f9a1 Añadir el esqueleto de la lógica de tareas
git -C superficial log --oneline -- app.js
# → e9a2c5f Cambio número 5La diferencia no es cosmética: en el clon superficial el fichero parece haber nacido completo en la última confirmación. Cualquier investigación sobre cuándo se introdujo una línea —git log, git blame o git bisect— dará una respuesta falsa. Por eso --depth sirve para compilar, no para investigar.
4. Convertirlo en completo:
cd ~/practica/superficial
git rev-parse --is-shallow-repository # → true
git fetch --unshallow
git rev-parse --is-shallow-repository # → false
git log --oneline | wc -l # → 5Ya no aparece grafted y el historial coincide con el del clon completo.
Solución al Ejercicio 3
1. Carla se incorpora:
git clone [email protected]:equipo/gestor-tareas.gitClon completo y normal. Es su copia de trabajo diaria, así que nada de --depth: necesitará blame e historial. SSH si tiene claves configuradas; HTTPS si aún no.
2. Servidor de integración continua:
Es el caso de manual para el clon superficial: compila y descarta, el historial no aporta nada y la descarga se minimiza. HTTPS con token es lo habitual en CI porque evita gestionar claves SSH.
3. Proyecto nuevo:
No hay nada que clonar: el proyecto nace aquí. git init <nombre> crea además la carpeta.
4. Consultar la versión v1.0 sin tocar el trabajo actual:
Un segundo clon en otra carpeta y con otro nombre deja su copia de trabajo intacta. Quedará en detached HEAD, que para consultar es correcto. (Solución alternativa y más elegante, que verá en el módulo 6: git worktree add.)
5. Migración de servidor:
--mirror es la opción correcta, no --bare a secas: replica todas las referencias —ramas, etiquetas y referencias remotas— y no solo las ramas locales. Es la forma estándar de mover un repositorio íntegro entre servidores.
6. La trampa. Aquí no hay que clonar sobre la carpeta existente, y de hecho Git no lo permitiría: git clone exige un directorio vacío o inexistente. Pero el problema de fondo es otro: la carpeta de Carla viene de un .zip, así que no tiene historial ni relación alguna con el repositorio del equipo. Conectarla a mano solo generaría conflictos y confusión.
La respuesta correcta es descartar esa carpeta y clonar de verdad:
mv gestor-tareas gestor-tareas-zip-viejo # por si acaso
git clone [email protected]:equipo/gestor-tareas.gitSi Carla hubiera hecho cambios en la copia del .zip, se copian a mano al clon recién hecho y se confirman allí como cambios normales. La regla general: una carpeta descargada en .zip no es un repositorio y no se convierte en uno con git init; para unirse a un proyecto existente se clona.
Conclusión
Bruno ya forma parte del proyecto. En esta lección hemos visto que:
git clonehace cinco cosas, no una: crea el directorio, lo inicializa, descarga toda la base de datos de objetos, registra el origen como remotooriginy crea la rama local volcando sus ficheros al directorio de trabajo.- El clon trae el historial completo, y esa es la esencia del modelo distribuido: Bruno puede consultar, comparar y confirmar sin red.
- Hay tres protocolos habituales: HTTPS (universal, con token), SSH (cómodo para el día a día, con claves) y ruta local (instantáneo, para copias y pruebas). Se distinguen a simple vista por la forma de la URL.
- Puedes elegir el nombre del directorio, la rama de destino con
--branchy la profundidad del historial con--depth. - Los clones superficiales son excelentes para CI y pésimos para trabajar, porque rompen
log,blameybisect. La decisión es reversible congit fetch --unshallow. initycloneresponden a preguntas distintas:initcuando el proyecto nace contigo,clonecuando te unes a uno que ya existe.- El clon solo trae lo confirmado. Lo que esté sin confirmar en el origen no viaja.
Ana y Bruno tienen ya cada uno su repositorio: una lo creó, el otro lo clonó. A partir de aquí, ambos hacen exactamente lo mismo todos los días: editar ficheros, decidir qué cambios agrupar y registrarlos en el historial.
Ese ciclo —editar, preparar, confirmar— es el latido de Git y el asunto de la siguiente lección, Flujo de Trabajo Básico de Git. Allí pondremos en movimiento las tres zonas que conoces desde el módulo 1, seguiremos el ciclo de vida completo de un fichero desde que Git no lo conoce hasta que queda confirmado, y aprenderemos a leer git status —en su forma larga y en la abreviada— como la brújula que te dice, en todo momento, dónde estás.
Dominando Git: De Principiante a Avanzado
Módulo 1: Introducción a Git
- ¿Qué es Git?
- Instalando Git
- Terminología Básica de Git
- El Modelo de Datos de Git
- Configurando Git
- Configuración Inicial
Módulo 2: Operaciones Básicas de Git
- Creando un Repositorio
- Clonando un Repositorio
- Flujo de Trabajo Básico de Git
- Preparando y Confirmando Cambios
- Inspeccionando Cambios con git diff
- Visualizando el Historial de Confirmaciones
Módulo 3: Ramas y Fusión
- Entendiendo las Ramas
- Creando y Cambiando Ramas
- Fusionando Ramas
- Estrategias de Fusión
- Resolviendo Conflictos de Fusión
- Gestión de Ramas
Módulo 4: Trabajando con Repositorios Remotos
- Entendiendo los Repositorios Remotos
- Agregando un Repositorio Remoto
- Autenticación con Repositorios Remotos
- Obteniendo y Extrayendo Cambios
- Enviando Cambios
- Rastreando Ramas
Módulo 5: Operaciones Avanzadas de Git
- Rebase
- Rebase Interactivo
- Cherry-Picking de Confirmaciones
- Guardando Cambios Temporales
- Etiquetando Confirmaciones
- Revirtiendo Confirmaciones
Módulo 6: Herramientas y Técnicas de Git
- Usando Git Hooks
- Git Bisect
- Git Blame
- Git Log y Alias
- Submódulos de Git
- Múltiples Copias de Trabajo con git worktree
Módulo 7: Estrategias de Colaboración y Flujo de Trabajo
- Forks y Pull Requests
- Revisiones de Código con Git
- Flujo de Trabajo Git Flow
- GitHub Flow
- Trunk Based Development
- Integración Continua con Git
Módulo 8: Mejores Prácticas y Consejos de Git
- Escribiendo Buenos Mensajes de Confirmación
- Manteniendo un Historial Limpio
- Ignorando Archivos con .gitignore
- Atributos de Fichero con .gitattributes
- Mejores Prácticas de Seguridad
- Consejos de Rendimiento
Módulo 9: Solución de Problemas y Depuración
- Problemas Comunes de Git
- Deshaciendo Cambios
- Resolviendo Divergencias con el Remoto
- Recuperando Confirmaciones Perdidas
- Tratando con Repositorios Corruptos
- Técnicas Avanzadas de Depuración
