Hasta ahora, todo pasaba en un solo repositorio, el tuyo. Pero Git está pensado para trabajar con otros: cada uno tiene su copia entera del repositorio (con toda la historia) y las copias se ponen al día unas con otras. Lo normal es que haya un repositorio en un servidor que todos usan de punto de encuentro: a ese, desde tu copia, lo llamas un remoto.
En este tema trabajas en Viajes Brisa, una agencia con dos oficinas, Madrid (la tuya) y Lisboa (donde está Rui). La web de la agencia vive en Git, en el servidor srv-git, y cada oficina tiene su copia. Como siempre, cada sección tiene un ejercicio con una terminal.
Clonar: tu copia del repositorio
Para empezar a trabajar en un repositorio que ya existe, lo clonas: Git trae toda la historia
y te deja la última versión en una carpeta. La dirección del repositorio de la agencia es
git@srv-git:agencia/web.git (se entra por ssh, como el usuario git, al repositorio
agencia/web.git).
tecnico@pc-madrid:~$ git clone git@srv-git:agencia/web.git Cloning into 'web'... remote: Enumerating objects: 6, done. remote: Counting objects: 100% (6/6), done. remote: Compressing objects: 100% (5/5), done. remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0 Receiving objects: 100% (6/6), done.
Las líneas que empiezan por remote: las escribe el servidor mientras prepara lo que manda (los
objetos: commits, árboles y archivos). La carpeta se llama como el repositorio, web, sin el
.git. Dentro, Git ya ha apuntado de dónde viene, con el nombre origin:
tecnico@pc-madrid:~/web$ git remote -v origin git@srv-git:agencia/web.git (fetch) origin git@srv-git:agencia/web.git (push)
Y hay ramas nuevas: las de seguimiento, como origin/main, que son la foto de cómo estaba
main en srv-git la última vez que hablaste con él. No las tocas tú: las mueve Git al subir y al
traer. git branch -a las enseña todas:
tecnico@pc-madrid:~/web$ git branch -a * main remotes/origin/HEAD -> origin/main remotes/origin/main
Tu main sigue a origin/main: por eso git status dice ahora cómo vas respecto a ella.
tecnico@pc-madrid:~/web$ git status On branch main Your branch is up to date with 'origin/main'. nothing to commit, working tree clean
Ejercicio
Tu copia de la web
La web de la agencia está en srv-git: git@srv-git:agencia/web.git. Haz tu copia en ~/web y mira de dónde viene.
Preparando la máquina…
Subir lo tuyo: git push
Trabajas como siempre: cambias, git add, git commit. El commit está solo en tu copia, y
git status te lo recuerda:
tecnico@pc-madrid:~/web$ git status On branch main Your branch is ahead of 'origin/main' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working tree clean
git push lo sube a srv-git: manda los objetos que allí faltan y mueve allí main a tu
commit. La última línea dice qué rama se movió y de dónde a dónde:
tecnico@pc-madrid:~/web$ git push Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Delta compression using up to 2 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 377 bytes | 377.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 To srv-git:agencia/web.git 72f1dfc..378749a main -> main
Ahora origin/main también está en tu commit, y git status vuelve a decir up to date. Si no
había nada nuevo que subir, git push dice Everything up-to-date.
Ejercicio
La oferta de Oporto
El viaje a Oporto baja de 199 € a 179 €. En tu copia (~/web), cámbialo en ofertas.txt, guárdalo en un commit y súbelo a srv-git, para que Lisboa lo tenga.
Preparando la máquina…
Traer lo de los demás: git pull
Rui, desde Lisboa, sube sus cambios a srv-git. Para tenerlos en tu copia, git pull: trae lo
nuevo del servidor (mueve origin/main) y lo junta con tu main. Si tú no tenías nada nuevo,
juntar es solo avanzar (Fast-forward, como en el tema 3):
tecnico@pc-madrid:~/web$ git pull remote: Enumerating objects: 6, done. remote: Counting objects: 100% (6/6), done. remote: Compressing objects: 100% (3/3), done. remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (4/4), 425 bytes | 425.00 KiB/s, done. From srv-git:agencia/web 72f1dfc..8e87f8c main -> origin/main Updating 72f1dfc..8e87f8c Fast-forward destinos/sintra.html | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 destinos/sintra.html
La parte de From es lo que trajo (origin/main avanzó); lo de debajo, el merge con tu main. En
git log verás el commit de Rui, con su nombre como autor.
Ejercicio
Lo nuevo de Lisboa
Rui, desde Lisboa, ha subido a srv-git la página de Sintra. Trae lo nuevo a tu copia (~/web) y mira quién lo hizo.
Preparando la máquina…
Cuando srv-git tiene algo que tú no: el push rechazado
Tú hiciste un commit (la página de Toledo) y, mientras, Rui subió el suyo (la de Sintra). Si
ahora intentas subir, srv-git lo rechaza: aceptarlo borraría el commit de Rui de main.
tecnico@pc-madrid:~/web$ git push To srv-git:agencia/web.git ! [rejected] main -> main (fetch first) error: failed to push some refs to 'srv-git:agencia/web.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Lo que pide es traer lo de Rui y juntarlo con lo tuyo antes de subir. Pero git pull a secas
tampoco lo hace todavía: como las dos copias han hecho commits (han divergido), Git quiere que
le digas cómo juntarlas:
tecnico@pc-madrid:~/web$ git pull From srv-git:agencia/web 72f1dfc..8e87f8c main -> origin/main hint: You have divergent branches and need to specify how to reconcile them. hint: You can do so by running one of the following commands sometime before hint: your next pull: hint: hint: git config pull.rebase false # merge (the default strategy) hint: git config pull.rebase true # rebase hint: git config pull.ff only # fast-forward only ... fatal: Need to specify how to reconcile divergent branches.
Hay dos maneras, las del tema 4:
git pull --no-rebase: un merge, con su commit de merge (Git abre el editor con el mensajeMerge branch 'main' of srv-git:agencia/web; basta con guardarlo).git pull --rebase: rehace tus commits encima de los de Rui, en línea, sin merge.
Para no tener que decirlo cada vez, se elige una con git config pull.rebase false (merge) o
true (rebase). Con el merge, la historia queda así:
tecnico@pc-madrid:~/web$ git log --oneline --graph * c8848a6 (HEAD -> main) Merge branch 'main' of srv-git:agencia/web |\ | * 8e87f8c (origin/main, origin/HEAD) Página de Sintra * | 3751407 Página de Toledo |/ * 72f1dfc La web de la agencia
Ya tienes lo de los dos, así que git push sube sin problema. Si lo tuyo y lo de Rui tocaban las
mismas líneas, el pull se queda a medias con un conflicto, y se resuelve como en el tema 4.
Ejercicio
Dos oficinas a la vez
Tienes en tu copia un commit sin subir (la página de Toledo), pero Rui subió antes la de Sintra. Sube lo tuyo a srv-git sin perder lo de Rui.
Preparando la máquina…
Una rama nueva en srv-git: git push -u
Las ramas que creas son tuyas hasta que las subes. Si haces una rama oporto y pruebas
git push, Git no sabe adónde mandarla:
tecnico@pc-madrid:~/web$ git push fatal: The current branch oporto has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin oporto
git push -u origin oporto (la -u es --set-upstream) la sube a origin con el mismo
nombre y, además, hace que tu oporto siga a la de allí: desde entonces, en esa rama bastan
git push y git pull, y git status dice cómo vas.
tecnico@pc-madrid:~/web$ git push -u origin oporto Enumerating objects: 6, done. Counting objects: 100% (6/6), done. Delta compression using up to 2 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (4/4), 404 bytes | 404.00 KiB/s, done. Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 To srv-git:agencia/web.git * [new branch] oporto -> oporto Branch 'oporto' set up to track remote branch 'oporto' from 'origin'.
git branch -vv enseña qué rama sigue cada una (entre corchetes) y si vas por delante
(ahead) o por detrás (behind):
tecnico@pc-madrid:~/web$ git branch -vv main 72f1dfc [origin/main] La web de la agencia * oporto 55061b2 [origin/oporto] Página de Oporto
Al revés también funciona: si Rui sube una rama verano y tú haces git switch verano (después
de traerla), Git crea tu verano siguiendo a origin/verano.
Ejercicio
Oporto, para revisar
Prepara la página de Oporto (destinos/oporto.html) en una rama nueva, oporto, y súbela a srv-git para que Rui la revise. Que tu rama siga a la de srv-git (así, después, bastan git push y git pull); main no se toca.
Preparando la máquina…
Mirar antes de juntar: git fetch
git pull trae y junta de una vez. A veces conviene ver antes qué viene. git fetch hace
solo la primera mitad: trae lo nuevo y mueve origin/main, sin tocar tu main ni tus
archivos.
tecnico@pc-madrid:~/web$ git fetch remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 374 bytes | 374.00 KiB/s, done. From srv-git:agencia/web 72f1dfc..d9ced03 main -> origin/main
Ahora git status sabe que vas por detrás. Y puedes mirar qué trae: git log main..origin/main
enseña los commits que están en origin/main y no en tu main, y git diff main origin/main, qué
cambian:
tecnico@pc-madrid:~/web$ git log --oneline main..origin/main d9ced03 (origin/main, origin/HEAD) Lisboa, más barata
tecnico@pc-madrid:~/web$ git diff main origin/main diff --git a/ofertas.txt b/ofertas.txt index ad37cf9..255fe0a 100644 --- a/ofertas.txt +++ b/ofertas.txt @@ -1,5 +1,5 @@ Ofertas de la semana -Lisboa: 149 € +Lisboa: 139 € Oporto: 199 € Sevilla: 129 €
Si te parece bien, lo juntas con git merge origin/main (que es lo que habría hecho git pull):
tecnico@pc-madrid:~/web$ git merge origin/main Updating 72f1dfc..d9ced03 Fast-forward ofertas.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Ejercicio
Antes de juntar, mirar
Rui avisa de que ha subido un cambio en las ofertas. Antes de juntarlo con tu copia (~/web), tráelo sin juntar, mira qué cambia y, después, júntalo.
Preparando la máquina…
Más cosas de los remotos
git remote add nombre direcciónañade otro remoto (al clonar ya tienesorigin);git remote renamele cambia el nombre,git remote removelo quita ygit remote show origincuenta lo que sabe de él (sus ramas y cuáles siguen las tuyas).- Un repositorio que empezó con
git init(y no congit clone) no tiene ningún remoto, ygit pushdiceNo configured push destination. Se le pone congit remote add origin dirección, ygit push -u origin mainlo sube a un repositorio vacío del servidor (en srv-git los crea el administrador) y deja tumainsiguiendo a la de allí. git push origin --delete veranoborra la ramaveranode srv-git (no hace falta tenerla en tu copia;git branch -dsolo borra la tuya).- Cuando alguien borra una rama en srv-git, tu
origin/veranose queda hasta que hacesgit fetch --prune. Si tuveranola seguía,git branch -vvla marca[origin/verano: gone]: la de allí ya no está. git ls-remote originpregunta al servidor qué ramas tiene ahora mismo, sin traer nada.
Resumen
| Orden | Qué hace |
|---|---|
git clone dirección |
tu copia de un repositorio, con su historia y el remoto origin |
git remote -v |
los remotos de tu copia y sus direcciones |
git push |
sube tus commits de la rama actual a la que sigue |
git pull |
trae lo nuevo y lo junta con tu rama (--no-rebase: merge; --rebase: en línea) |
git fetch |
solo trae: mueve origin/main, sin tocar tu rama |
git log main..origin/main |
los commits que vienen y aún no tienes |
git merge origin/main |
junta lo traído con tu rama |
git push -u origin rama |
sube una rama nueva y hace que la tuya la siga |
git branch -vv / -a |
qué rama sigue cada una / también las de seguimiento |
git push origin --delete rama |
borra una rama del servidor |
git fetch --prune |
trae y quita las de seguimiento cuya rama ya no está |