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

  1. La situación de Bruno
  2. git clone en su forma más simple
  3. Qué hace realmente git clone, paso a paso
  4. Protocolos: HTTPS, SSH y ruta local
  5. Clonar en un directorio con otro nombre
  6. Clonar una rama concreta con --branch
  7. Clones superficiales con --depth
  8. --single-branch y otras opciones útiles
  9. init frente a clone: la diferencia conceptual
  10. Comprobaciones después de clonar

  1. 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]

  1. git clone en su forma más simple

Bruno se sitúa en la carpeta donde guarda sus proyectos y ejecuta:

cd ~/Proyectos
git clone https://git.ejemplo.es/equipo/gestor-tareas.git
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.

cd gestor-tareas
ls -a
.  ..  .git  app.js  estilos.css  index.html  README.md
git log --oneline
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:

git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

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.

  1. Qué hace realmente git clone, paso a paso

Un 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:

fatal: destination path 'gestor-tareas' already exists and is not an empty directory.

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:

ls -F .git
branches/  config  description  FETCH_HEAD  HEAD  hooks/  index  info/  logs/  objects/  packed-refs  refs/

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:

git count-objects -v
count: 0
size: 0
in-pack: 24
packed: 24
prune-packable: 0
garbage: 0
size-pack: 5

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:

git remote -v
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:

cat .git/config
[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/main

origin 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.

  1. 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:

git clone https://git.ejemplo.es/equipo/gestor-tareas.git
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.git

Se 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.git

Ruta 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-trabajo

Es 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:

git clone --no-hardlinks /Volumes/compartido/repos/gestor-tareas.git

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:

git clone file:///Volumes/compartido/repos/gestor-tareas.git

Cuidado con clonar de un repositorio no bare. Se puede clonar de un repositorio normal (por ejemplo, directamente de ~/proyectos/gestor-tareas de 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".

  1. Clonar en un directorio con otro nombre

Basta con añadir el nombre deseado como segundo argumento:

git clone https://git.ejemplo.es/equipo/gestor-tareas.git gestor
Cloning into 'gestor'...

El repositorio es idéntico; solo cambia la carpeta que lo contiene. Es útil en tres situaciones:

  • Evitar colisiones: ya tienes una carpeta gestor-tareas de 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á prefieras web-cliente-acme.

Si quieres clonar en el directorio actual y no en uno nuevo, usa . como destino. El directorio debe estar vacío:

mkdir gestor-tareas && cd gestor-tareas
git clone https://git.ejemplo.es/equipo/gestor-tareas.git .

  1. Clonar una rama concreta con --branch

Por defecto, el clon te deja situado en la rama por defecto del origen (main). Con --branch (o -b) eliges otra:

git clone --branch desarrollo https://git.ejemplo.es/equipo/gestor-tareas.git
git branch --show-current
desarrollo

Dos precisiones importantes:

  1. Se descarga todo el repositorio igualmente. --branch no filtra lo que llega; solo decide en qué rama te deja. Las demás siguen ahí, accesibles.
  2. 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):
git clone --branch v1.0 https://git.ejemplo.es/equipo/gestor-tareas.git gestor-v1
Note: switching to 'v1.0'.
You are in 'detached HEAD' state...

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.

  1. Clones superficiales con --depth

En 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:

git clone --depth 1 https://git.ejemplo.es/equipo/gestor-tareas.git
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.

git log --oneline
c5d9b1e (grafted, HEAD -> main, origin/main) Documentar la instalación en el README

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
Compilar / ejecutar el proyecto
Crear confirmaciones nuevas
git log completo No, solo la última
git blame fiable No
git bisect para buscar un fallo No
Comparar con versiones antiguas 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, sin bisect y 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:

git fetch --unshallow

O traerte más profundidad de la que tienes:

git fetch --deepen 50

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. Conservan log, blame y bisect y suelen ser mejor opción que --depth para repositorios grandes. Lo veremos en Escalando Git para Proyectos Grandes.

  1. --single-branch y otras opciones útiles

--single-branch descarga únicamente la rama indicada, ignorando las demás:

git clone --single-branch --branch main https://git.ejemplo.es/equipo/gestor-tareas.git

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.git

Esto 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)

  1. init frente a clone: la diferencia conceptual

Es 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.

  1. 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
# → 4

Y 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 clone sin fijarte y estás dentro de otro proyecto, acabas con un repositorio anidado que confunde a Git y a tus compañeros. Comprueba con pwd antes, o con git rev-parse --show-toplevel.
  • Usar --depth 1 en la copia de trabajo diaria. Ahorras unos segundos una vez y pierdes blame, bisect y todas las comparaciones históricas durante meses. Resérvalo para CI y contenedores.
  • Confundir la URL SSH con la HTTPS. git@host:grupo/repo.git es SSH (sin ://, con dos puntos); https://host/grupo/repo.git es HTTPS. Si copias la de SSH sin tener claves configuradas, el clon fallará con Permission 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 .gitignore haga 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 --progress o añade --depth si 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 -5 y é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:

  1. Crea ~/practica/ana/gestor-tareas con un README.md y un app.js, e inicialízalo con dos confirmaciones.
  2. Crea a partir de él un repositorio bare en ~/practica/servidor/gestor-tareas.git que haga de punto central.
  3. Clónalo en ~/practica/bruno/gestor-tareas, simulando a Bruno.
  4. Demuestra con comandos que Bruno tiene: las dos confirmaciones, el remoto origin apuntando al bare, y la rama main siguiendo a origin/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:

  1. Compara el número de objetos de cada uno.
  2. Compara la salida de git log --oneline.
  3. Intenta ejecutar git log sobre un fichero concreto en ambos y explica la diferencia.
  4. 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.

  1. Carla empieza hoy y necesita gestor-tareas en su Windows 11, con todo el historial, para trabajar a diario.
  2. El servidor de integración continua debe compilar la última versión de main en cada cambio, lo más rápido posible.
  3. Ana quiere empezar un proyecto nuevo, informes-mensuales, que todavía no existe en ninguna parte.
  4. Bruno necesita revisar cómo era estilos.css en la versión etiquetada v1.0, sin dejar de trabajar en su copia actual.
  5. El equipo migra de servidor y hay que llevarse el repositorio íntegro, con todas las ramas y etiquetas.
  6. Carla ya tiene la carpeta gestor-tareas con el proyecto descargado en .zip de 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 --oneline
7d2f9a1 (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
Cloning into bare repository 'gestor-tareas.git'...
done.

--bare crea la réplica sin directorio de trabajo, que es exactamente lo que debe ser un repositorio central:

ls -F gestor-tareas.git
# → config  description  HEAD  hooks/  info/  objects/  packed-refs  refs/

Paso 3 — el clon de Bruno:

mkdir -p ~/practica/bruno
cd ~/practica/bruno
git clone ~/practica/servidor/gestor-tareas.git
cd gestor-tareas

Paso 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/main

Que 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.git

Los 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: 4

2. 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 5

3. 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 5

La 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                  # → 5

Ya 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.git

Clon 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:

git clone --depth 1 --branch main https://git.ejemplo.es/equipo/gestor-tareas.git

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:

cd ~/proyectos
git init informes-mensuales

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:

git clone --branch v1.0 https://git.ejemplo.es/equipo/gestor-tareas.git ~/consulta-v1

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:

git clone --mirror https://git.ejemplo.es/equipo/gestor-tareas.git gestor-tareas.git

--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.git

Si 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 clone hace cinco cosas, no una: crea el directorio, lo inicializa, descarga toda la base de datos de objetos, registra el origen como remoto origin y 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 --branch y la profundidad del historial con --depth.
  • Los clones superficiales son excelentes para CI y pésimos para trabajar, porque rompen log, blame y bisect. La decisión es reversible con git fetch --unshallow.
  • init y clone responden a preguntas distintas: init cuando el proyecto nace contigo, clone cuando 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

Módulo 2: Operaciones Básicas de Git

Módulo 3: Ramas y Fusión

Módulo 4: Trabajando con Repositorios Remotos

Módulo 5: Operaciones Avanzadas de Git

Módulo 6: Herramientas y Técnicas de Git

Módulo 7: Estrategias de Colaboración y Flujo de Trabajo

Módulo 8: Mejores Prácticas y Consejos de Git

Módulo 9: Solución de Problemas y Depuración

Módulo 10: Git en el Mundo Real

© Copyright 2026. Todos los derechos reservados