Los repositorios remotos son parte importante en la colaboración distribuida de Git. Este HowTo pretende enseñar qué son, cómo trabajar, recuperar y sincronizar Repositorios de forma local y remota.
¿Qué es un Repositorio Remoto?
Cuando clonamos un repositorio de GitHub, lo que estamos haciendo es que nuestro repositorio local interactúe con dicho repositorio remoto. De esta forma estamos dejando que otros programadores o colaboradores, desde sus propias estaciones de trabajo, hagan copias locales del proyecto independientes unas de otras. Por lo que cuando se necesitemos compartir cambios, tan sólo necesitamos clonar el código, realizar los cambios, y enviarlos de nuevo al repositorio remoto.
Existen muchos servicios, que permiten alojar repositorios remotos, como GitHub, GitBucket o Gitlab, pero también disponemos de la posibilidad de crear nuestros propios repositorios privados en nuestra propia red. Al poder instalar estos repositorios en cualquier Sistema Operativo, como Linux, Windows o MacOs, podemos tener mayor privacidad, control y personalización de estos.
Cuando trabajamos con repositorios remotos, necesitamos seguir una serie de pautas al realizar cambios. Primero se modifican los ficheros, luego se incluyen se añaden a un área intermedia o de ensayo (add), para luego confirmar (commit) los cambios localmente. Una vez hecho esto, tenemos que comprobar (fetch) si nuestro repositorio remoto dispone de nuevos cambios, si hay cambios los fusionamos (merge) si fuera necesario y por último enviaremos (push) los cambios realizados a nuestro repositorio remoto.
Para conectar con un repositorio remoto, podemos usar diferentes protocolos. HTTP se usa normalmente para permitir el acceso sólo lectura (clonar, pero no enviar). Por el contrario HTTPS y SSH proporcionan métodos para autenticar usuarios, lo que nos permite modificar los repositorios.
El comando que usamos para clonar un repositorio es git clone.
1 2 3 4 5 6 7 |
$ git clone https://github.com/jl3377/automatic-backups-python.git Cloning into 'automatic-backups-python'... remote: Enumerating objects: 3, done. remote: Counting objects: 100% (3/3), done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 7.23 KiB | 7.23 MiB/s, done. |
¿Cómo trabajar con Repositorios Remotos?
Cuando clonamos un repositorio remoto, Git configura el repositorio remoto con el nombre de origen del repositorio. Para comprobar la configuración de un repositorio remoto usamos el comando git remote -v, en el mismo directorio donde está ubicado el repositorio.
1 2 3 4 |
$ cd automatic-backups-python $ git remote -v origin https://github.com/jl3377/automatic-backups-python.git (fetch) origin https://github.com/jl3377/automatic-backups-python.git (push) |
Pero, ¿a qué corresponden estas URLs?. fetch
se usa para recuperar datos del repositorio remoto y push
para enviar datos al repositorio remoto. Es normal que apunten al mismo lugar, pero podemos hacer que la primera apunte a un protocolo HTTP de sólo lectura y la segunda a un protocolo HTTPS o SSH para controlar los accesos. Esto sólo es eficaz, siempre que el contenido que se lee del repositorio, sea el mismo que se ha enviado.
Los repositorios remotos tienen como nombre origin
, que es asignado por defecto. Esto nos permite rastrear más de un repositorio remoto en el mismo directorio y será útil si trabajamos en diferentes equipos pero con proyectos relacionados entre sí.
Para obtener más información sobre un repositorio remoto usamos el comando git remote show origin. De esta forma podemos ver las URLs de lectura y escritura, sus ramas locales y remotas. Cuando el repositorio disponga de más ramas, la información comenzará a ser más detallada y compleja.
1 2 3 4 5 6 7 8 9 10 11 |
$ git remote show origin * remote origin Fetch URL: https://github.com/jl3377/automatic-backups-python.git Push URL: https://github.com/jl3377/automatic-backups-python.git HEAD branch: main Remote branch: main tracked Local branch configured for 'git pull': main merges with remote main Local ref configured for 'git push': main pushes to main (up to date) |
Puede que te preguntes, ¿a qué corresponden estas ramas remotas: remote branch
?. Cuando trabajamos con repositorios remotos, Git usa ramas remotas para mantener copias de los datos en el repositorio remoto. Para saber las ramas con las que está trabajando nuestro repositorio usaremos el comando git branch -r.
1 2 3 |
$ git branch -r origin/HEAD -> origin/main origin/main |
Estas ramas son de “sólo lectura” y podemos ver todos los cambios que se han confirmado (commits) en ellas al igual que hacemos con nuestras ramas locales. Lo que no vamos a poder hacer es realizar cambios directamente en ellas. Para poder hacerlo necesitamos seguir un flujo de trabajo específico que nos permitirá modificar su contenido:
- Primero, recuperamos (pull) todos los cambios que se han producido en el repositorio remoto hacia nuestro repositorio local.
- Luego los fusionamos (merge) y los confirmamos (commit) con nuestros propios cambios, si fuera necesario.
- Por último, enviamos (push) los cambios realizados al repositorio remoto.
Recuerda, que también podemos usar git status para verificar el estado de nuestros cambios en las ramas remotas. Al trabajar con un repositorio remoto, git status, nos aportará información adicional, por lo que nos avisará si nuestra rama está actualizada con la rama origin/main.
1 2 3 4 5 |
$ git status On branch main Your branch is up to date with 'origin/main'. nothing to commit, working tree clean |
En caso de no estar actualizada, vemos como actuar a continuación.
Recuperando cambios de un Repositorio Remoto
Para comprobar si se han realizado cambios en un repositorio remoto, podemos empezar usando el comando git remoto show origin.
1 2 3 4 5 6 7 8 9 10 11 |
$ git remote show origin * remote origin Fetch URL: https://github.com/jl3377/automatic-backups-python.git Push URL: https://github.com/jl3377/automatic-backups-python.git HEAD branch: main Remote branch: main tracked Local branch configured for 'git pull': main merges with remote main Local ref configured for 'git push': main pushes to main (local out of date) |
Si nos fijamos bien, Git nos avisa que nuestro repositorio local está obsoleto (local out of date) y no coincide con el repositorio remoto. Es probable que alguien de nuestro equipo o que tiene acceso al repositorio, haya realizado modificaciones recientes en él, por lo que necesitamos actualizarlo.
Esto se produce porque Git no mantiene las copias de los repositorios sincronizadas automáticamente, sino que espera que ejecutemos una serie de órdenes o comandos, cuando estemos preparados para mover los datos. Para realizar esta sincronización usamos el comando git fetch, que descarga todas las confirmaciones realizadas en el repositorio remoto, hacia nuestro repositorio local.
1 2 3 4 5 6 7 8 |
$ 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 2), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 710 bytes | 710.00 KiB/s, done. From https://github.com/jl3377/automatic-backups-python 1dbf23b..25abc97 main -> origin/main |
El contenido se ha descargado automáticamente a nuestro repositorio local, pero la descarga de los datos, no se ha reflejado automáticamente. Estos cambios están en una rama oculta llamada FETCH_HEAD. Si ejecutamos el comando git checkout ó git checkout FETCH_HEAD, podemos comprobar qué ramas y cambios necesitan ser confirmados.
1 2 3 |
$ git checkout Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded. (use "git pull" to update your local branch) |
Si necesitamos más información, también podemos recurrir al comando git log, para comprobar que fué modificado recientemente en el repositorio remoto. Vemos que el último commit apunta a la rama HEAD, origin/main.
1 2 3 4 5 6 7 8 9 10 11 |
$ git log origin/main commit 25abc97dc7148d64407c6f7611dc27a529eb5ebe (HEAD, origin/main, origin/HEAD) Author: José Luis Rojo Sánchez <jose@artegrafico.net> Date: Sun Jan 3 20:29:29 2021 +0100 update readme description commit 1dbf23b068b78ab2a2cd1bbc699826a96d08ec71 (main) Author: José Luis Rojo <jose@artegrafico.net> Date: Sat Jan 2 19:02:09 2021 -0800 Initial Commit |
Para integrar estos datos a nuestro repositorio local, necesitamos realizar una operación de fusión (merge), que fusiona la rama origin/main del repositorio remoto, en nuestra rama main local. Se podrían producir conflictos durante la fusión, pero eso lo veremos en otro post.
1 2 3 4 5 |
$ git merge origin/main Updating 25abc97..8163396 Fast-forward README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) |
Resumiendo, usaremos fetch cuando necesitamos revisar qué cambios se han producido en un repositorio remoto antes de realizar una fusión (merge).
Existe otro comando llamado git pull que realiza este proceso conjuntamente (git fetch + git merge), lo que nos permite ahorrar tiempo. Su funcionamiento, lo veremos a continuación.
Sincronizar Repositorio Local con Remoto
Ya hemos visto cómo funcionan git fetch junto a git merge. Al ser comandos que se usan frecuentemente, Git nos ofrece el comando git pull, que realiza ambos por nosotros. De tal forma que al ejecutarlo, se obtiene una copia actualizada del repositorio remoto y la intenta fusionar automáticamente con nuestro repositorio local si fuera necesario.
1 2 3 4 5 6 7 8 9 |
$ git pull remote: Enumerating objects: 4, done. remote: Counting objects: 100% (4/4), done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 657 bytes | 657.00 KiB/s, done. From https://github.com/jl3377/automatic-backups-python * [new branch] experimental -> origin/experimental Already up to date. |
Si comprobamos el log, vemos que primero se recupera el contenido de la rama origin/main, para luego actualizarse usando el método Fast-forward. Si existen cambios en ficheros de la rama main, estos se actualizan automáticamente pero, ¿Qué ocurre si se crearon nuevas ramas? En este caso, vemos que alguien creó una nueva rama llamada experimental.
Para traernos toda la información de esta nueva rama necesitamos ejecutar el comando git checkout. Una vez ejecutado, se crea y nos mueve automáticamente a esta nueva nueva rama, copiando todos los datos de la rama remota en ella. De esta forma ya estamos preparados para trabajar en dicha rama junto con los colaboradores que estén trabajando en ella.
1 2 3 |
$ git checkout experimental Branch 'experimental' set up to track remote branch 'experimental' from 'origin'. Switched to a new branch 'experimental' |
Cuando necesitemos obtener el contenido de ramas remotas sin fusionarlas automáticamente con el contenido de nuestro repositorio local, podemos ejecutar el comando git remote update. De esta forma obtenemos todo el contenido de las ramas remotas para luego poderlas llamar (checkout) o fusionarlas (merge) según sea el caso.