Cerramos el módulo 3 con un problema abierto: todo el trabajo de gestor-tareas vive dentro de un único .git/, el del portátil Ubuntu de Ana. Las ramas de Bruno solo existían en nuestra imaginación, y Carla lleva tres módulos esperando en su Windows 11 a que alguien le diga de dónde descargar el proyecto.
Este módulo cierra ese círculo, y empieza por donde hay que empezar: entendiendo qué es un remoto. Y la respuesta va a decepcionar a quien esperase magia, porque un remoto no es un servidor, ni un servicio, ni una copia sincronizada de tu proyecto. Un remoto es un nombre corto para una URL. Nada más. Todo lo demás —fetch, pull, push, las ramas de seguimiento— se construye encima de esa idea minúscula.
En esta lección no vamos a registrar ningún remoto todavía (eso es la lección siguiente). Vamos a construir el modelo mental correcto: por qué en un sistema distribuido no existe técnicamente un servidor central, qué es un repositorio bare y por qué el del servidor no tiene ficheros con los que trabajar, qué son exactamente esas referencias origin/main que llevan apareciendo desde la lección 02-02, y qué añaden plataformas como GitHub o GitLab sobre el Git que ya conoces.
Contenido
- Qué es un remoto: un nombre corto para una URL
- Por qué no hay servidor central (técnicamente)
- El repositorio de referencia: una convención, no una imposición
- Repositorios bare: el servidor no necesita ficheros
- Las referencias remotas:
.git/refs/remotes/ origin/maines una referencia local de solo lectura- Convenciones de nombre:
origin,upstreamy los demás - Plataformas de alojamiento: qué añaden sobre Git
- El mapa mental completo
- Qué es un remoto: un nombre corto para una URL
Empecemos por la definición exacta, porque casi todo el desconcierto posterior nace de no tenerla clara.
Un remoto es una entrada en la configuración de tu repositorio que asocia un nombre corto a una URL (y a unas reglas sobre qué referencias traer de allí).
Eso es literalmente todo. Cuando escribes origin, Git busca en .git/config una sección [remote "origin"], lee la URL que hay dentro y la usa. Es exactamente el mismo mecanismo que un alias de shell o una entrada en /etc/hosts: un nombre cómodo para algo largo e incómodo de teclear.
Compara las dos formas de hacer lo mismo:
# Sin remoto registrado: la URL entera, cada vez
git fetch https://git.ejemplo.es/equipo/gestor-tareas.git main
# Con el remoto registrado: un nombre corto
git fetch origin mainLas dos funcionan. La primera demuestra el punto: Git puede hablar con cualquier repositorio dándole su URL directamente, sin registrar nada. Los remotos existen para no repetir la URL cuarenta veces al día y para poder asociarle configuración adicional.
Lo que un remoto NO es
Es igual de importante saber qué no hay detrás de esa palabra:
| Un remoto no es… | Por qué la gente lo cree |
|---|---|
| Una carpeta sincronizada tipo Dropbox | Nada se sincroniza solo: los objetos viajan únicamente cuando ejecutas fetch, pull o push |
| Una conexión permanente | Git es completamente asíncrono: trabaja sin red y solo se conecta en esos tres comandos |
| Una copia idéntica de tu repositorio | El remoto tiene sus propias ramas, que pueden ir por delante o por detrás de las tuyas |
| Un servidor con inteligencia | El otro extremo ejecuta Git, igual que tú; no hay lógica de negocio ahí |
| Algo obligatorio | Un repositorio Git es perfectamente funcional sin ningún remoto, como el de Ana durante tres módulos |
Ese último punto merece énfasis. Todo lo que has hecho hasta ahora —confirmar, ramificar, fusionar, resolver conflictos, consultar el historial— funciona sin red y sin remotos. Los remotos no añaden capacidades a Git: añaden transporte. Son el mecanismo por el que los objetos de un .git/objects/ acaban en otro .git/objects/.
Las URL que admite un remoto
Un remoto puede apuntar a sitios muy distintos, y no todos están en Internet:
# HTTPS: lo más habitual con plataformas de alojamiento
https://git.ejemplo.es/equipo/gestor-tareas.git
# SSH, forma abreviada tipo scp (la más vista)
[email protected]:equipo/gestor-tareas.git
# SSH, forma de URL completa (equivalente a la anterior)
ssh://[email protected]/equipo/gestor-tareas.git
# Ruta local: una carpeta del propio ordenador o de un disco montado
/home/ana/copias/gestor-tareas.git
# Ruta local en formato file://
file:///home/ana/copias/gestor-tareas.git
# Protocolo git:// (sin autenticación, solo lectura, prácticamente en desuso)
git://git.ejemplo.es/equipo/gestor-tareas.gitLos protocolos ya los viste en la lección 02-02 al hablar de git clone; son exactamente los mismos, porque clone no es más que "crear un repositorio + registrar un remoto + traérselo todo".
Un detalle que conviene interiorizar: una ruta local es una URL perfectamente válida. Puedes tener un remoto que apunte a una carpeta de tu propio disco, y todo el módulo funciona igual. Esto es magnífico para practicar, y lo usaremos en los ejercicios: no necesitas cuenta en ningún sitio ni conexión a Internet para aprender remotos.
- Por qué no hay servidor central (técnicamente)
En la lección 01-01 vimos la diferencia entre control de versiones centralizado y distribuido. Ahora toca la consecuencia práctica de aquello, que es más radical de lo que suele parecer.
En Subversion o CVS, el servidor es estructuralmente distinto del cliente: contiene el historial, decide qué números de revisión se asignan y es imprescindible para casi cualquier operación. Sin servidor, no hay control de versiones.
En Git no existe esa distinción. Todos los repositorios son iguales. El repositorio que hay en git.ejemplo.es ejecuta el mismo Git, guarda los mismos objetos con el mismo formato y no tiene ningún privilegio especial sobre el de Ana. Si el servidor ardiera esta tarde, cualquiera de los tres podría montar uno nuevo con su propia copia y el equipo seguiría trabajando en cinco minutos.
flowchart TB
subgraph ANA["Portátil de Ana · Ubuntu"]
A1["Repositorio completo<br/>.git/objects + .git/refs<br/>+ directorio de trabajo"]
end
subgraph BRUNO["MacBook de Bruno · macOS"]
B1["Repositorio completo<br/>.git/objects + .git/refs<br/>+ directorio de trabajo"]
end
subgraph CARLA["Portátil de Carla · Windows 11"]
C1["Repositorio completo<br/>.git/objects + .git/refs<br/>+ directorio de trabajo"]
end
subgraph SRV["git.ejemplo.es · repositorio bare"]
S1["Repositorio completo<br/>objects + refs<br/><b>sin</b> directorio de trabajo"]
end
A1 <-->|push / fetch| S1
B1 <-->|push / fetch| S1
C1 <-->|push / fetch| S1
A1 <-.->|técnicamente posible:<br/>intercambio directo| B1
Fíjate en la línea discontinua entre Ana y Bruno. No es un adorno: es Git funcionando exactamente como fue diseñado. Bruno puede registrar el portátil de Ana como remoto y traerse sus commits directamente, sin que el servidor intervenga. Linus Torvalds diseñó Git para el kernel de Linux, donde cientos de personas se intercambian parches y ramas sin un repositorio central obligatorio.
Entonces, ¿por qué todo el mundo usa un servidor?
Porque las razones para tener un repositorio de referencia no son técnicas, sino organizativas:
- Disponibilidad. El portátil de Ana está apagado por las noches, en el avión y cuando se va de vacaciones. Un servidor está encendido siempre.
- Punto de acuerdo. Con un repositorio de referencia, la pregunta "¿cuál es la versión buena de
main?" tiene una respuesta única y aburrida. Sin él, hay tres respuestas y tres opiniones. - Copia de seguridad implícita. Si el disco de Bruno muere, su trabajo enviado sigue existiendo.
- Control de acceso. Alguien tiene que decidir quién puede escribir en
main. Eso requiere un sitio donde aplicar esas reglas. - Automatización. Las pruebas automáticas, los despliegues y los avisos necesitan un punto fijo al que engancharse (módulo 7).
- Direccionalidad de red. Ana no puede conectarse al portátil de Carla: está detrás del router de su casa, con IP cambiante y sin puertos abiertos. Un servidor con dirección estable resuelve el problema de que todos puedan llegar a algún sitio común.
Esta última razón es la más subestimada y probablemente la más decisiva en la práctica.
- El repositorio de referencia: una convención, no una imposición
De todo lo anterior sale una idea que conviene fijar bien:
El repositorio "oficial" de un proyecto lo es porque el equipo ha acordado que lo sea, no porque Git lo distinga de ninguna manera.
Si mañana el equipo decide que el repositorio bueno pasa a estar en otro servidor, basta con que los tres cambien una línea de configuración —la URL de su remoto origin— y ese otro será el oficial. Git no se entera del cambio y no le importa. Es una migración de cinco segundos por persona, algo impensable en un sistema centralizado.
Esa flexibilidad tiene una cara incómoda: Git no protege nada por sí mismo. No hay un concepto nativo de "esta rama es sagrada" ni de "solo Ana puede escribir aquí". Cualquiera con permiso de escritura puede, en principio, reescribir main en el servidor. Las protecciones que usan los equipos —ramas protegidas, revisiones obligatorias, comprobaciones que deben pasar antes de integrar— las añaden las plataformas de alojamiento encima de Git, no Git.
Lo veremos con detalle en el módulo 7, pero interioriza ya la separación: Git mueve objetos; la plataforma pone las reglas.
- Repositorios bare: el servidor no necesita ficheros
En la lección 02-01 dejamos una idea a medias: git init --bare crea un repositorio sin directorio de trabajo, y dijimos que se entendería al hablar de remotos. Ha llegado el momento.
Qué es exactamente
Un repositorio normal tiene esta forma:
gestor-tareas/ ├── .git/ ← el repositorio (objetos, referencias, configuración) │ ├── objects/ │ ├── refs/ │ ├── HEAD │ └── config ├── index.html ← el directorio de trabajo ├── estilos.css ├── app.js └── README.md
Un repositorio bare tiene esta otra:
gestor-tareas.git/ ├── objects/ ← lo que en el otro estaba dentro de .git/ ├── refs/ ├── HEAD ├── config ├── description └── hooks/
Es el contenido de .git/ promovido a la raíz, y ni un solo fichero del proyecto. Por eso se llama bare, "desnudo": no tiene copia de trabajo con la que vestirse.
Por convención, los directorios de repositorios bare terminan en .git —gestor-tareas.git— para que se vea de un vistazo qué son. De ahí viene, precisamente, el .git final de las URL que llevas viendo todo el curso.
Por qué el repositorio del servidor tiene que ser bare
Imagina por un momento que no lo fuera: que en el servidor hubiera un repositorio normal, con su index.html y su app.js en el disco, y con HEAD apuntando a main.
Ana ejecuta git push y envía tres commits nuevos a main. ¿Qué debería pasar en el servidor?
- Si Git actualizara la rama
mainy los ficheros del directorio de trabajo, estaría modificando ficheros de una máquina en la que a lo mejor hay alguien editándolos en ese preciso momento. Podría destruir trabajo sin avisar. - Si actualizara la rama pero no los ficheros, el repositorio del servidor quedaría en un estado incoherente:
git statusallí diría que hay decenas de ficheros modificados y borrados, cuando en realidad nadie ha tocado nada.
Ninguna de las dos opciones es aceptable, así que Git elige una tercera: negarse. Si intentas enviar a la rama que está activa en un repositorio no bare, obtienes esto:
! [remote rejected] main -> main (branch is currently checked out) error: failed to push some refs to '/home/ana/copias/gestor-tareas'
Con un repositorio bare el problema desaparece de raíz: como no hay directorio de trabajo, no hay nada que pueda quedar incoherente. Recibir un push se reduce a añadir objetos y mover un puntero, que es una operación limpia y segura.
| Repositorio normal | Repositorio bare | |
|---|---|---|
| Directorio de trabajo | Sí | No |
| Se crea con | git init / git clone |
git init --bare / git clone --bare |
| Estructura | proyecto/.git/… |
proyecto.git/… (todo en la raíz) |
| Sirve para | Trabajar: editar, confirmar | Compartir: recibir y servir |
Admite git push a su rama activa |
No | Sí (no tiene rama "activa" en ese sentido) |
| Se puede editar código en él | Sí | No hay ficheros que editar |
git status |
Informativo | Error: no hay copia de trabajo |
Lo que hay al otro lado de GitHub, GitLab o Gitea es siempre un repositorio bare. Cuando clonas, la plataforma sirve los objetos desde uno; cuando envías, los recibe en uno.
Crear uno para practicar
Esto te va a servir en todos los ejercicios del módulo, así que compruébalo ahora:
Exactamente lo que esperábamos: el contenido de un .git/, sin ficheros de proyecto. Y su configuración lo declara:
Ese git -C <ruta> es un truco cómodo: ejecuta el comando como si estuvieras dentro de ese directorio, sin tener que ir y volver.
Este directorio es un "servidor" perfectamente válido. Puedes enviarle cambios y clonar de él. La única diferencia con GitHub es que está en tu disco y no tiene interfaz web.
- Las referencias remotas:
.git/refs/remotes/
.git/refs/remotes/Aquí está la pieza central de la lección, y probablemente el concepto que más malentendidos genera en todo Git.
En el módulo 3 aprendiste que una rama es un fichero de 41 bytes en .git/refs/heads/ con un hash dentro. Pues bien: existe un segundo directorio hermano, .git/refs/remotes/, con ficheros exactamente iguales.
Miremos el repositorio que Bruno clonó en la lección 02-02:
Dos ficheros con el mismo hash dentro. El primero es la rama main de Bruno; el segundo es la referencia remota origin/main.
La estructura completa de referencias queda así:
| Directorio | Contiene | Ejemplo de nombre |
|---|---|---|
.git/refs/heads/ |
Tus ramas locales | main, funcionalidad/exportar-csv |
.git/refs/remotes/<remoto>/ |
Referencias remotas | origin/main, origin/documentacion/notas |
.git/refs/tags/ |
Etiquetas (lección 05-05) | v1.2.0 |
Y, como viste en la lección 03-01, muchas de estas referencias pueden acabar comprimidas en .git/packed-refs en lugar de existir como ficheros sueltos. Se consultan igual:
git rev-parse resuelve cualquier nombre de referencia a su hash, esté donde esté guardada. Es la forma robusta de consultarlas y la que debes usar en scripts.
origin/main es una referencia local de solo lectura
origin/main es una referencia local de solo lecturaAhora la afirmación importante, la que hay que entender para que el resto del módulo tenga sentido:
origin/mainno está en el servidor. Está en tu disco. Es una nota que Git se dejó a sí mismo diciendo "la última vez que hablé conorigin, su ramamainestaba en este commit".
Piénsalo como una fotografía con fecha, no como una ventana en directo. Y de ahí se derivan tres consecuencias que conviene tener grabadas:
Primera: origin/main puede estar desactualizado, y normalmente lo está. Si Bruno envió tres commits hace diez minutos y tú no has ejecutado ningún fetch, tu origin/main sigue señalando el commit de ayer. Git no tiene forma de saberlo: no hay ninguna conexión abierta ni ningún aviso. Solo se entera cuando le pides que hable con el servidor.
Segunda: solo se actualiza en momentos concretos. Las referencias remotas cambian cuando ejecutas git fetch, git pull (que hace un fetch por dentro), git clone o un git push con éxito. En cualquier otro momento están congeladas.
Tercera: no puedes trabajar directamente sobre ella. Es de solo lectura desde el punto de vista de tu trabajo diario:
Git no te cambia a una rama origin/main, porque no es una rama tuya: te deja en HEAD desacoplado sobre ese commit, exactamente el estado que estudiaste en la lección 03-02. Y si confirmas ahí, tus commits quedarán colgando sin ninguna rama que los sostenga.
Del mismo modo, no puedes confirmar sobre ella ni fusionar dentro de ella. Lo que sí puedes —y harás constantemente— es usarla como referencia, igual que cualquier otro nombre de commit:
# ¿Qué tengo yo que el servidor no tenía la última vez que miré?
git log --oneline origin/main..main
# ¿Qué tenía el servidor que yo no tengo?
git log --oneline main..origin/main
# ¿Qué diferencias de contenido hay?
git diff origin/main main
# Crear una rama a partir de ella
git switch -c correccion/urgente origin/main
# Fusionar su contenido en mi rama actual
git merge origin/mainToda la sintaxis de rangos y referencias del módulo 2 (.., ~, ^) funciona con ellas sin ninguna diferencia, porque son referencias normales y corrientes: solo cambia el directorio donde viven y quién las actualiza.
El diagrama que hay que recordar
flowchart LR
subgraph LOCAL["Repositorio local de Bruno"]
M["main<br/>(rama local)<br/>refs/heads/main"]
OM["origin/main<br/>(referencia remota)<br/>refs/remotes/origin/main"]
end
subgraph SERVER["git.ejemplo.es (bare)"]
SM["main<br/>(la rama de verdad)<br/>refs/heads/main"]
end
M -->|"git merge origin/main<br/>(integración local)"| OM
OM -->|"git fetch<br/>(actualiza la foto)"| SM
M -->|"git push<br/>(envía objetos y mueve la rama)"| SM
Tres cosas distintas con nombres parecidos: tu main, tu origin/main y el main del servidor. La lección 04-06 está dedicada íntegramente a esa distinción, porque es la fuente de la mayoría de las confusiones. Por ahora quédate con esto: las dos primeras están en tu disco; la tercera no.
Cómo verlas
Ese origin/HEAD es un extra que crea git clone: recuerda cuál es la rama por defecto del servidor. Es lo que permite escribir git log origin como atajo de git log origin/main, y lo que hace que un clon te sitúe en main y no en cualquier otra rama.
- Convenciones de nombre:
origin, upstream y los demás
origin, upstream y los demásEl nombre de un remoto es libre. Puede ser origin, servidor, pepito o x. Pero hay convenciones muy asentadas que conviene respetar, porque cualquier persona que se incorpore al proyecto —o cualquier tutorial que leas— las da por supuestas:
| Nombre | Significado convencional | Cuándo aparece |
|---|---|---|
origin |
El repositorio del que clonaste; el de referencia del equipo | Lo pone git clone automáticamente |
upstream |
El repositorio original del que salió tu copia personal | Al trabajar con forks (módulo 7) |
fork |
Tu copia personal, cuando origin es el proyecto original |
Convención alternativa a la anterior |
staging, produccion |
Repositorios de despliegue | En flujos de despliegue por push (módulo 10) |
backup, espejo |
Copia secundaria del repositorio | Redundancia |
Sobre upstream conviene decir dos palabras ahora para evitar una confusión clásica, porque la palabra se usa en Git con dos significados completamente distintos:
upstreamcomo nombre de remoto: el proyecto original del que hiciste un fork. Es una simple convención de nombre, sin nada especial. Se desarrolla en la lección 07-01.- upstream como rama de seguimiento: la referencia remota con la que está emparejada una rama local tuya. Esto sí es un concepto de Git con configuración propia, y es el tema de la lección 04-06.
Son cosas distintas que comparten palabra. Cuando leas "la rama no tiene upstream", se refiere al segundo sentido.
Recomendación práctica: llama origin al repositorio de referencia de tu equipo y no te compliques. La convención está tan asentada que desviarse de ella solo genera preguntas.
- Plataformas de alojamiento: qué añaden sobre Git
Llegados aquí conviene ser tajante para deshacer un malentendido muy extendido: GitHub no es Git. GitHub es una empresa que aloja repositorios Git y les añade servicios alrededor. Git funcionaba antes de que GitHub existiera y funcionaría igual si desapareciera mañana.
Todo lo que has hecho en tres módulos, y todo lo que harás en este, funciona contra un repositorio bare en un servidor con SSH, sin ninguna plataforma de por medio. Las plataformas aportan lo que Git deliberadamente no hace.
| Plataforma | Modelo | Rasgos característicos |
|---|---|---|
| GitHub | Servicio comercial; opción autoalojada (Enterprise Server) | El mayor ecosistema; Actions para automatización; enorme comunidad de proyectos abiertos |
| GitLab | Servicio comercial; edición comunitaria autoalojable y gratuita | Plataforma DevOps completa: CI/CD, registro de contenedores, gestión de incidencias, despliegue |
| Gitea / Forgejo | Software libre autoalojado | Muy ligero (un solo binario); ideal para servidores pequeños o redes internas |
| Bitbucket | Servicio comercial (Atlassian) | Integración estrecha con Jira y el resto de herramientas de Atlassian |
| Codeberg | Servicio sin ánimo de lucro sobre Forgejo | Alojamiento libre para proyectos de código abierto |
| SourceHut | Servicio comercial minimalista | Flujo basado en correo y parches, al estilo del kernel de Linux |
Qué añade una plataforma exactamente
- Alojamiento con disponibilidad y copias de seguridad: la máquina encendida que ningún portátil puede ser.
- Control de acceso: quién lee, quién escribe, quién administra; y ramas protegidas, que impiden reescribir
maino borrarla. - Propuestas de cambio (pull requests en GitHub, merge requests en GitLab): la conversación, la revisión y la aprobación de un conjunto de commits antes de integrarlo. Es una capa social sobre el
git mergeque ya conoces. Módulo 7. - Gestión de incidencias, hitos y tableros de trabajo.
- Integración continua: ejecutar pruebas y despliegues automáticamente en cada envío. Módulos 7 y 10.
- Interfaz web: navegar el código, leer el historial, comparar ramas y ver los diffs sin clonar nada.
- Documentación:
README.mdrenderizado, wikis, páginas web del proyecto. - Búsqueda y descubrimiento: encontrar código y proyectos, que es lo que convirtió a GitHub en lo que es.
Lo importante para este módulo: ninguno de esos servicios cambia cómo funciona fetch, push o merge. Aprender Git bien te sirve en las seis plataformas por igual, y cambiar de una a otra es cambiar una URL.
- El mapa mental completo
Antes de pasar a la práctica, unifiquemos todo lo visto en un solo esquema del recorrido que hace un commit desde el teclado de Ana hasta el disco de Carla:
flowchart TB
subgraph A["Ana · Ubuntu"]
A1["Directorio<br/>de trabajo"] -->|"git add"| A2["Índice"]
A2 -->|"git commit"| A3["Repositorio local<br/>.git/objects"]
end
A3 -->|"git push origin main"| S["Servidor bare<br/>git.ejemplo.es"]
subgraph C["Carla · Windows 11"]
C3["Repositorio local<br/>.git/objects<br/>+ refs/remotes/origin/main"] -->|"git merge origin/main"| C1["Directorio<br/>de trabajo"]
end
S -->|"git fetch origin"| C3
Presta atención a la asimetría de la parte inferior. El git fetch de Carla solo llega hasta su repositorio local: actualiza origin/main y descarga objetos, pero no toca ni un fichero de su disco de trabajo. Hace falta un segundo paso —una integración, normalmente un merge— para que el trabajo de Ana aparezca en sus ficheros. Esa separación en dos pasos es el corazón de la lección 04-04, y es lo que distingue fetch de pull.
Y observa también lo que no aparece en el diagrama: nada sucede solo. Cada flecha es un comando que alguien ejecuta.
Errores Comunes y Consejos
Error 1: creer que origin es una palabra reservada de Git. No lo es: es el nombre que git clone pone por defecto al remoto, y podría ser cualquier otro. En git fetch origin, la palabra origin es un nombre configurado en tu .git/config, no una parte de la sintaxis del comando.
Error 2: pensar que origin/main consulta el servidor. Es un fichero de tu disco con un hash dentro. Si no has hecho fetch, puede llevar días desactualizado. Cuando alguien te diga "pues en el servidor ya está", tu primer reflejo debe ser git fetch, no discutir.
Error 3: creer que el servidor "tiene" tu repositorio. Tu repositorio es tuyo y está completo en tu disco. El servidor tiene otro repositorio, que casualmente comparte historia con el tuyo. Por eso puedes trabajar sin red durante una semana entera.
Error 4: intentar enviar a un repositorio no bare. Si montas tu propio servidor con git init en lugar de git init --bare, el primer push fallará con branch is currently checked out. Los repositorios que reciben envíos deben crearse con --bare.
Error 5: confundir la plataforma con Git. "GitHub no me deja hacer force push a main" no es una limitación de Git, sino una regla de rama protegida configurada en la plataforma. Distinguir qué capa te está hablando ahorra muchísimo tiempo depurando.
Consejo 1: monta un bare local para practicar. git init --bare /tmp/servidor/proyecto.git te da un servidor real, sin cuentas, sin contraseñas y sin Internet. Todo el módulo se puede hacer así, y es la mejor forma de aprender sin miedo a romper nada.
Consejo 2: acostúmbrate a git remote -v como primer comando al llegar a un repositorio desconocido. Junto con git status y git log --oneline -5, es lo que te dice dónde estás y con quién hablas.
Consejo 3: piensa siempre en "tres cosas distintas". main, origin/main y el main del servidor. En cuanto un problema de remotos te desconcierte, pregúntate de cuál de las tres estás hablando. Nueve de cada diez veces, ahí está la respuesta.
Ejercicios
Ejercicio 1: anatomía de un repositorio bare
Crea un repositorio bare y uno normal en /tmp y responde con comandos:
- ¿Qué diferencias hay en la estructura de directorios de cada uno?
- ¿Qué dice
core.bareen la configuración de cada uno? - ¿Qué ocurre si ejecutas
git statusdentro del bare? - ¿Cuánto ocupa cada uno recién creado y por qué la diferencia es mínima?
Ejercicio 2: referencias remotas al desnudo
Partiendo de un repositorio bare con contenido, clónalo dos veces simulando a Bruno y a Carla. Después:
- Localiza en el disco el fichero de la referencia
origin/mainde Carla y muestra su contenido. - Comprueba que ese hash coincide con el de su rama local
main. - Haz que Bruno envíe un commit nuevo al bare.
- Sin ejecutar
fetch, comprueba que elorigin/mainde Carla sigue apuntando al commit antiguo. Explica por qué. - Comprueba con
git rev-parsecuál es el estado real de la rama en el bare.
Ejercicio 3: explicarlo con tus palabras
Carla acaba de incorporarse y te escribe: "Entonces, cuando hago git clone, ¿me descargo una carpeta compartida? ¿Si cambio algo se entera el resto?"
Redacta una respuesta de entre 150 y 250 palabras que aclare: qué es un remoto, por qué su repositorio es completo e independiente, qué es origin/main y cuándo se sincroniza algo. Sin usar la palabra "mágico" y sin dar por sabido nada que no se haya visto en el curso.
Soluciones
Solución 1:
Initialized empty Git repository in /tmp/comparativa/normal/.git/ Initialized empty Git repository in /tmp/comparativa/desnudo.git/
Ya en el mensaje se ve la diferencia: uno inicializa normal/.git/ y el otro desnudo.git/ directamente.
El repositorio normal solo contiene .git; el bare tiene ese mismo contenido en su raíz.
# 2. La marca en la configuración
git -C /tmp/comparativa/normal config core.bare
git -C /tmp/comparativa/desnudo.git config core.bareEl mensaje es literal: status compara el directorio de trabajo con el índice, y aquí no hay directorio de trabajo que comparar.
Prácticamente idénticos: en ambos casos lo que ocupa es la estructura vacía de directorios y los ficheros de plantilla de hooks/. La diferencia real aparecería con contenido, y aun así sería pequeña: el bare se ahorra solo la copia desplegada de los ficheros, no los objetos.
Solución 2:
# Preparar el "servidor" con algo de contenido
mkdir -p /tmp/practica && cd /tmp/practica
git init --bare servidor.git
# Un repositorio de partida que lo alimente
git clone servidor.git inicial
cd inicial
echo "<h1>Gestor de tareas</h1>" > index.html
git add . && git commit -m "Estructura inicial del gestor de tareas"
git push origin main
cd ..
# Los dos clones
git clone servidor.git bruno
git clone servidor.git carla# 1. El fichero de la referencia remota de Carla
find /tmp/practica/carla/.git/refs -type f
cat /tmp/practica/carla/.git/refs/remotes/origin/main/tmp/practica/carla/.git/refs/heads/main /tmp/practica/carla/.git/refs/remotes/origin/main /tmp/practica/carla/.git/refs/remotes/origin/HEAD 4f8c2a1e9b3d7f6a2c8e4b1d9f3a7c5e2b8d6f4a
(El hash será distinto en tu máquina; lo importante es la estructura.)
Recién clonado, las dos referencias señalan el mismo commit.
# 3. Bruno trabaja y envía
cd /tmp/practica/bruno
echo "body { font-family: sans-serif; }" > estilos.css
git add . && git commit -m "Añadir estilos base del listado"
git push origin mainEl mismo hash de antes. Y la explicación es exactamente la idea central de la lección: origin/main es un fichero en el disco de Carla que nadie ha tocado. Bruno ha escrito en el bare, no en el portátil de Carla. Git no tiene ningún mecanismo de aviso: la referencia solo se actualizará cuando Carla ejecute fetch o pull.
Un hash distinto: el commit de Bruno. La referencia de Carla está desactualizada, y lo estará hasta que hable con el servidor.
# Comprobación final: tras el fetch, se pone al día
git -C /tmp/practica/carla fetch origin
git -C /tmp/practica/carla rev-parse origin/mainY fíjate en un detalle que anticipa la lección 04-04: main de Carla sigue en el commit antiguo y sus ficheros no han cambiado. El fetch solo ha actualizado la foto.
Solución 3:
Hola, Carla. No, no es una carpeta compartida: es bastante mejor que eso.
Cuando clonas, no te descargas un enlace a algo remoto, sino una copia completa e independiente del proyecto, con todo el historial, todas las ramas y toda la base de datos de objetos. A partir de ese momento puedes confirmar, crear ramas, fusionarlas y consultar el historial de hace dos años sin conexión y sin permiso de nadie. Tu repositorio es tan válido como el del servidor.
Lo que sí guarda el clon es de dónde vino: registra la URL bajo el nombre corto
origin. Eso es un remoto, ni más ni menos: un nombre para una URL.Sobre si el resto se entera: no, y esto es importante. Nada se sincroniza automáticamente. Tus commits están solo en tu disco hasta que ejecutas
git push, y los de los demás no llegan hasta que ejecutasgit fetchogit pull. Verás referencias que se llamanorigin/main: no son el servidor, son una nota que Git guarda en tu propio disco con el aspecto que tenía el servidor la última vez que hablaste con él. Si llevas dos días sin hacerfetch, esa nota tiene dos días de antigüedad.En resumen: trabajas en local, y decides tú cuándo enviar y cuándo recibir.
Conclusión
Esta lección ha construido el modelo mental que sostiene todo el módulo. Lo esencial:
- Un remoto es un nombre corto para una URL guardado en
.git/config. No es una copia sincronizada, ni una conexión abierta, ni nada obligatorio. Git puede hablar con un repositorio dándole la URL directamente; el remoto solo evita repetirla. - Técnicamente no hay servidor central. Todos los repositorios Git son iguales y completos. El repositorio "de referencia" lo es por acuerdo del equipo, y las razones para tener uno son organizativas: disponibilidad, punto de acuerdo, copia de seguridad, control de acceso, automatización y direccionalidad de red.
- Un repositorio bare es un repositorio sin directorio de trabajo: el contenido de
.git/en la raíz. Es la forma correcta de montar un repositorio que recibe envíos, porque así no puede quedar en un estado incoherente. Lo que hay detrás de GitHub o GitLab es siempre un bare. - Las referencias remotas viven en
.git/refs/remotes/y son ficheros idénticos a los de las ramas locales.origin/maines una referencia local de solo lectura que recuerda dónde estaba el remoto la última vez que se habló con él. Se actualiza solo confetch,pull,cloneopush. main,origin/mainy elmaindel servidor son tres cosas distintas. Las dos primeras están en tu disco.originyupstreamson convenciones de nombre, no palabras reservadas. Y ojo: upstream significa además otra cosa —la rama de seguimiento— que veremos en la lección 04-06.- Las plataformas de alojamiento añaden servicios sobre Git (control de acceso, propuestas de cambio, integración continua, interfaz web), pero no cambian cómo funciona Git. Aprender Git te sirve en todas por igual.
Lo que viene
Ya sabes qué es un remoto. En la lección 04-02: Agregando un Repositorio Remoto pasamos a la práctica: Ana publica por fin gestor-tareas. Registraremos el remoto con git remote add, inspeccionaremos lo que aparece con git remote -v y git remote show, aprenderemos a renombrarlo, eliminarlo y cambiarle la URL, y —sobre todo— abriremos .git/config para desmenuzar con calma esa línea fetch = +refs/heads/*:refs/remotes/origin/* que llevamos dos módulos viendo de refilón sin explicar. Es el refspec, la pieza que casi nadie entiende y que, una vez comprendida, hace que fetch y push dejen de parecer arbitrarios.
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
