En els blocs anteriors, s'ha presentat l'estructura d'un repositori de Git i les accions bàsiques
per a fer-hi canvis. No obstant això, totes aquestes accions s'han fet sobre un repositori local,
és a dir, un repositori que es troba en el teu dispositiu i els canvis del qual no s'han publicat enlloc.
Aquest bloc se centra en els repositoris remots: repositoris allotjats en un servidor,
que permeten l'accés d'altres persones i la col·laboració en el desenvolupament de projectes.
Figura 1. Estructura d'un repositori local i remot.
Preparació del repositori local
En aquests apunts es treballa sobre un nou repositori local, que s'inicialitza amb les ordres següents:
#!/bin/bash# Elimina el repositori si existeixif[-d~/git_remots];thenrm-rf~/git_remots
fimkdir-p~/git_remots
cd~/git_remots
gitinit
gitbranch-mmain# (1)!echo"# Remots a Git">README.md
echo"Repositori del __Bloc: Remots__ del curs __\"Introducció a Git i GitHub Actions\"__">>README.md
gitaddREADME.md
gitcommit-m"Commit inicial"gitlga
Es canvia el nom de la branca principal a main.
jpuigcerver@fp:~$mkdir-p~/git_remots
jpuigcerver@fp:~$cd~/git_remots
jpuigcerver@fp:~/git_remots$gitinit
Initialized empty Git repository in ~/git_remots/.git/jpuigcerver@fp:~/git_remots(main)$gitbranch-mmain# (1)!jpuigcerver@fp:~/git_remots(main)$echo"# Remots a Git">README.md
jpuigcerver@fp:~/git_remots(main)$echo"Repositori del __Bloc: Remots__ del curs __\"Introducció a Git i GitHub Actions\"__">>README.md
jpuigcerver@fp:~/git_remots(main)$gitaddREADME.md
jpuigcerver@fp:~/git_remots(main)$gitcommit-m"Commit inicial"[main (root-commit) 2036c5a] Commit inicial 1 file changed, 2 insertions(+) create mode 100644 README.mdjpuigcerver@fp:~/git_remots(main)$gitlga
*2036c5a-(0 seconds ago)Commit inicial-Joan Puigcerver(HEAD -> main)
Es canvia el nom de la branca principal a main.
README.md
# Remots a GitRepositori del __Bloc: Remots__ del curs __"Introducció a Git i GitHub Actions"__
Crea el nou repositori en una carpeta independent per evitar problemes amb els exemples i exercicis anteriors.
Un repositori remot és una còpia d'un repositori de Git allotjada en un servidor
o en un altre lloc fora del teu sistema local. Aquesta còpia conté una rèplica completa
de la història del repositori, incloses totes les revisions i les branques.
Els repositoris remots permeten col·laborar i fer el seguiment del desenvolupament del codi
entre diverses persones, o bé treballar tu mateix des de diferents dispositius.
Figura 2. Repositori remot vinculat a diversos repositoris locals.
Les principals finalitats dels repositoris remots són:
Col·laboració: permeten que diverses persones treballen juntes en un mateix projecte.
Cada persona treballa en la seua còpia local del repositori i, una vegada fetes les modificacions,
puja els canvis al repositori remot perquè la resta de l'equip els puga vore i incorporar.
Còpia de seguretat: un repositori remot pot servir com a còpia de seguretat del projecte.
Si el teu sistema local es danya o es perd, encara tens accés a la història completa
i als fitxers del projecte mitjançant el repositori remot.
Distribució: els repositoris remots permeten distribuir el codi a altres llocs,
tant per a compartir-lo amb altres persones com per a desplegar el projecte en un servidor en línia.
Gràcies a aquestes característiques, Git s'ha convertit en una ferramenta clau en qualsevol desenvolupament,
i sobretot en els projectes de codi obert (open source), ja que permet que persones de tot el món
col·laboren en un mateix projecte de manera senzilla i distribuïda.
Els repositoris remots es poden allotjar en qualsevol màquina o servidor dedicat.
No obstant això, hi ha serveis en línia que faciliten la creació i la gestió de repositoris remots.
Alguns dels més coneguts són:
GitHub: servei creat en 2008 i adquirit per Microsoft en 2018.
És el servei d'allotjament de repositoris de Git més utilitzat.
Ofereix una opció gratuïta, que permet crear projectes públics i privats amb algunes restriccions,
i plans de pagament per a projectes empresarials.
GitLab: servei d'allotjament basat en una plataforma de codi obert.
Bitbucket: servei propietat de l'empresa Atlassian,
que s'integra estretament amb altres ferramentes d'aquesta empresa, com Jira.
Codeberg: servei gestionat per Codeberg e.V.,
una associació alemanya sense ànim de lucre. Està basat en el projecte de codi obert
Forgejo, de manera que la seua interfície i les seues funcionalitats
d'automatització resulten molt familiars per a qui ja coneix GitHub.
A diferència de GitHub o Bitbucket, Codeberg no és una empresa amb ànim de lucre:
es manté amb donacions, tot el seu programari és lliure i totes les característiques
(inclosos els repositoris privats i la CI/CD) són gratuïtes. Per aquest motiu, cada vegada més
projectes de codi obert opten per allotjar-se a Codeberg com a alternativa a les plataformes propietàries.
Fes clic en el botó New per a crear un repositori nou.
Omple el formulari amb la informació del repositori:
Nom: nom del repositori, que ha de ser únic en el teu compte de GitHub.
Descripció: (opcional) descripció del repositori.
Visibilitat: indica qui pot vore el repositori.
Públic: qualsevol persona pot vore el repositori,
però només les persones autoritzades poden fer-hi canvis.
Privat: només tu i les persones que autoritzes podeu vore el repositori
i fer-hi canvis.
README: indica si vols afegir un fitxer README al repositori.
.gitignore: indica si vols afegir un fitxer .gitignore per a ignorar fitxers en el repositori.
Llicència: indica si vols afegir una llicència al repositori.
Exemple: Creació d'un repositori a GitHub
Es crea un repositori amb les característiques següents:
Nom: git_remots.
Descripció: Repositori del Bloc: Remots del curs "Introducció a Git i GitHub Actions".
Visibilitat: públic.
README: no.
.gitignore: no.
Llicència: no.
Figura 1. Formulari de creació d'un repositori nou a GitHub.
Una vegada omplert el formulari, es fa clic en Create repository per a crear el repositori.
El repositori es crea buit i es mostra una pàgina com la següent:
Figura 2. Repositori buit creat a GitHub.
La Figura 4 mostra els passos per a enllaçar el repositori local
amb el repositori remot creat a GitHub. Els apartats següents expliquen aquestes ordres amb més detall.
El primer pas és enllaçar el Repositori local amb el Repositori remot que s'acaba de crear.
Per fer-ho, s'utilitza l'ordre git remote, que permet gestionar els repositoris remots
associats al repositori local:
gitremote[add|rename|remove|show][<options>]
Sense subordre: mostra els repositoris remots associats al repositori local.
[add]: (opcional) afegeix un repositori remot nou.
[rename]: (opcional) canvia el nom d'un repositori remot.
[remove]: (opcional) elimina un repositori remot.
[show]: (opcional) mostra informació detallada d'un repositori remot.
[<options>]: (opcional) opcions i arguments propis de cada subordre.
Per a afegir un repositori remot, s'utilitza l'ordre git remote add:
gitremoteadd<alies><url>
<alies>: nom o àlies amb què s'identifica el repositori remot en el repositori local.
Normalment, s'utilitza el nom origin per a referir-se al repositori remot principal.
<url>: URL del repositori remot.
Figura 3. Repositori local vinculat amb un repositori remot.
Si intentes publicar els canvis amb git push abans d'enllaçar cap remot, Git mostra un missatge d'error.
jpuigcerver@fp:~/git_remots(main)$gitpush
fatal: No configured push destination.Either specify the URL from the command-line or configure a remote repository using git remote add <name> <url>and then push using the remote name git push <name>To push to multiple remotes at once, configure a remote group using git config remotes.<groupname> "<remote1> <remote2>"and then push using the group name git push <groupname>
Exemple: Afegir un repositori remot
S'enllaça el repositori local amb el repositori remot creat anteriorment a GitHub,
la URL del qual és git@github.com:joapuiib/git_remots.git.
S'utilitza la URL SSH perquè és el mètode d'autenticació configurat.
De moment, les branques creades només existeixen en el repositori local, és a dir, en el teu dispositiu.
Per a publicar una branca i els seus canvis en el repositori remot, s'utilitza l'ordre git push:
gitpush[-u|--set-upstream][<remot>[<branca>]]
[-u | --set-upstream]: (opcional) associa la branca local amb la branca remota indicada
(upstream), de manera que les operacions git pull i git push futures
la utilitzen per defecte.
[<remot>]: (opcional) àlies del repositori remot.
Si no s'especifica, s'utilitza el remot associat prèviament amb --set-upstream.
[<branca>]: (opcional) nom de la branca local que es vol publicar.
Si no s'especifica, s'utilitza la branca actual (HEAD).
Figura 4. Publicació d'una branca local en una branca remota.
Exemple: Publicació i associació de la branca local i la remota
Inicialment, la branca main no està associada a cap branca remota.
Es pot comprovar amb git branch -vv, que no mostra cap branca remota entre claudàtors.
Per això, si s'executa git push, es mostra un missatge d'error que indica
que cal associar-hi una branca remota.
jpuigcerver@fp:~/git_remots(main)$gitlga
*2036c5a-(0 seconds ago)Commit inicial-Joan Puigcerver(HEAD -> main)jpuigcerver@fp:~/git_remots(main)$gitbranch-vv
* main 2036c5a Commit inicialjpuigcerver@fp:~/git_remots(main)$gitpush
fatal: The current branch main has no upstream branch.To push the current branch and set the remote as upstream, use git push --set-upstream origin mainTo have this happen automatically for branches without a trackingupstream, see 'push.autoSetupRemote' in 'git help config'.
A continuació, s'associen la branca main local i la remota amb l'ordre git push --set-upstream.
jpuigcerver@fp:~/git_remots(main)$gitpush--set-upstreamoriginmain
branch 'main' set up to track 'origin/main'.To github.com:joapuiib/git_remots.git * [new branch] main -> mainjpuigcerver@fp:~/git_remots(main)$gitbranch-vv
* main 2036c5a [origin/main] Commit inicialjpuigcerver@fp:~/git_remots(main)$gitlga
*2036c5a-(0 seconds ago)Commit inicial-Joan Puigcerver(HEAD -> main, origin/main)
S'observa que localment s'ha creat la referència origin/main, que apunta a la branca remota main.
A més, ara git branch -vv mostra [origin/main] al costat de la branca main,
és a dir, la branca remota associada. Finalment, els canvis s'han publicat correctament en el repositori remot:
Cada branca local es pot associar amb una branca remota mitjançant l'opció -u o --set-upstream
de l'ordre git push. Aquesta branca remota s'anomena upstream i inclou tant el remot
com el nom de la branca en aquest:
gitpush-u<remot><branca>
Per exemple, git push -u origin main publica la branca main en el remot origin
i, a més, associa la branca local main amb origin/main. Aquesta associació és
independent per a cada branca local: no afecta la resta de branques.
Gràcies a l'associació, Git sap on ha de publicar i d'on ha de portar els canvis quan s'executen
les ordres git push o git pull sense arguments. A més, git status l'utilitza
per indicar si la branca local va per davant o per darrere de la remota.
Per consultar la branca remota associada a cada branca local, s'utilitza l'ordre git branch -vv.
Vegeu-ne el resultat en l'exemple anterior.
L'opció push.autoSetupRemote fa que cada branca local s'associe automàticament amb la branca remota del mateix nom.
gitconfig--globalpush.autoSetupRemotetrue
L'associació d'una branca local es pot eliminar amb l'ordre git branch --unset-upstream:
gitbranch--unset-upstream[<branca>]
[<branca>]: (opcional) branca de la qual es vol eliminar l'associació.
Si no s'especifica, s'utilitza la branca actual.
L'ordre git clone copia un repositori remot en un repositori local del teu sistema,
des del qual pots fer canvis.
Aquesta ordre copia els continguts del Directori de treball i tota la informació del Repositori local,
inclosa la història de canvis. A més, configura automàticament el repositori remot amb l'àlies origin.
La sintaxi és la següent:
gitclone<url>[<directori>]
<url>: URL del repositori remot. Pot ser una URL HTTPS o SSH.
[<directori>]: (opcional) nom del directori on es copia el repositori.
Per defecte, es crea un directori amb el nom del repositori remot.
Com que els canvis ja estan publicats en el repositori remot, es pot clonar en el sistema local.
Per comprovar-ho, s'esborra el directori git_remots i es clona des del repositori remot.
jpuigcerver@fp:~/git_remots(main)$cd~
jpuigcerver@fp:~$rm-rf~/git_remots
jpuigcerver@fp:~$ls-l~/git_remots
ls: cannot access '~/git_remots': No such file or directoryjpuigcerver@fp:~$gitclonegit@github.com:joapuiib/git_remots.git
Cloning into 'git_remots'...done.jpuigcerver@fp:~$cd~/git_remots
jpuigcerver@fp:~/git_remots(main)$gitlga
*2036c5a-(0 seconds ago)Commit inicial-Joan Puigcerver(HEAD -> main, origin/main, origin/HEAD)
S'observa que s'ha clonat correctament el repositori git_remots,
que conté els fitxers i la història de canvis del repositori remot.
L'ordre git fetch actualitza en el repositori local la informació de les branques remotes
(origin/<branca>), però no aplica els canvis a les branques locals:
gitfetch[<options>][<remot>]
[<options>]: (opcional) opcions de l'ordre.
[<remot>]: (opcional) àlies del repositori remot. Per defecte, s'utilitza origin.
Figura 6. Sincronització entre repositoris amb git fetch.
Aquesta ordre és útil per a obtindre la informació dels canvis realitzats en el repositori remot
i decidir després si es volen incorporar al repositori local.
L'opció --prune elimina les referències de les branques remotes que ja no existeixen en el repositori remot.
Aquesta opció es pot activar per defecte amb l'ordre git config:
gitconfig--globalfetch.prunetrue
També es pot configurar perquè s'aplique en l'ordre git pull:
gitconfig--globalremote.origin.prunetrue
Preparació: Canvis en el repositori remot
Es fa un canvi en el repositori remot directament a GitHub.
Es crea un fitxer menjar.txt amb el contingut següent:
menjar.txt
Pa
Macarrons
Figura 6.1. Crear un fitxer nou a GitHub.
Figura 6.2. Afegir contingut a menjar.txt a GitHub.
Es crea un commit amb el missatge Menjar.
Figura 6.3. Crear un commit a GitHub.
Es comprova que el canvi s'ha fet correctament.
Figura 6.4. Canvi realitzat a GitHub.
Exemple: Sincronització entre repositoris (fetch)
En aquest moment, el repositori remot té un canvi que no figura en el repositori local.
Es poden produir conflictes, que cal resoldre manualment.
Executar directament git pullgenera un commit de fusió,
que potser no és desitjable si es vol mantindre una història lineal.
Per a evitar la fusió de branques divergents en git pull, hi ha dues opcions:
git pull --ff-only: incorpora els canvis de la branca remota
només si es pot fer una fusió directa (fast-forward).
Si no és possible, es mostra un error i no s'incorporen els canvis en la branca local.
Aquest comportament es pot configurar per defecte:
gitconfig--globalpull.ffonly
git pull --rebase: incorpora els canvis de la branca remota mitjançant un canvi de base (rebase),
és a dir, aplica els canvis de la branca local després dels canvis de la branca remota.
Aquest comportament també es pot configurar per defecte:
gitconfig--globalpull.rebasetrue
Exemple: Incorporació de canvis amb fusió directa (pull --ff-only)
El commitb460858 forma part de la branca remota origin/main, però no de la branca local main.
S'observa que la branca local main ha avançat fins al mateix commit que origin/main.
Preparació: Més canvis en el repositori remot
Fes els canvis següents en el repositori remot directament a GitHub.
Modifica el fitxer menjar.txt amb el contingut següent:
menjar.txt
Pa
Macarrons
Pomes
Crea un commit amb el missatge Més menjar.
Exemple: Incorporació de canvis amb fusió de branques divergents (pull --no-ff i pull --rebase)
Una de les situacions més habituals en què la branca local divergeix de la remota és
fer canvis en la branca local sense haver-la sincronitzat abans amb la branca remota associada.
En aquest cas, s'ha fet un altre canvi en el repositori remot que encara no s'ha incorporat.
Per a simular la situació anterior, es fa un canvi en la branca local main.
El canvi Més menjar no apareix en la branca remota origin/main
perquè no s'ha sincronitzat el repositori local amb el repositori remot.
Si ara s'intenta publicar aquest canvi en el repositori remot, Git mostra un missatge d'error,
perquè el repositori remot té canvis que no estan en el repositori local.
jpuigcerver@fp:~/git_remots(main)$gitpush
To github.com:joapuiib/git_remots.git ! [rejected] main -> main (fetch first)error: failed to push some refs to 'github.com:joapuiib/git_remots.git'hint: Updates were rejected because the remote contains work that you do nothint: have locally. This is usually caused by another repository pushing tohint: the same ref. If you want to integrate the remote changes, usehint: 'git pull' before pushing again.hint: See the 'Note about fast-forwards' in 'git push --help' for details.jpuigcerver@fp:~/git_remots(main)$gitfetch
From github.com:joapuiib/git_remots b460858..735c088 main -> origin/mainjpuigcerver@fp:~/git_remots(main)$gitlga
*5894304-(0 seconds ago)Beguda-Joan Puigcerver(HEAD -> main)| *735c088-(0 seconds ago)Més menjar-Joan Puigcerver(origin/main, origin/HEAD)|/ *b460858-(0 seconds ago)Menjar-Joan Puigcerver*2036c5a-(0 seconds ago)Commit inicial-Joan Puigcerver
S'observa que git push recomana fer un git pull per a incorporar els canvis,
ja que les dues branques han divergit.
No obstant això, git pull faria una fusió de branques divergents, que crearia un commit de fusió
i donaria com a resultat una història no lineal.
Tampoc no es poden incorporar els canvis amb una fusió directa (git pull --ff-only):
jpuigcerver@fp:~/git_remots(main)$gitpull--ff-only
hint: Diverging branches can't be fast-forwarded, you need to either:hint:hint: git merge --no-ffhint:hint: or:hint:hint: git rebasehint:hint: Disable this message with "git config set advice.diverging false"fatal: Not possible to fast-forward, aborting.
Per tant, els canvis s'han d'incorporar d'alguna de les dues maneres següents:
Amb un commit de fusió: git pull --no-ff.
És el procés que segueix git pull si no s'indica cap opció addicional.
Crea un commit de fusió, que no és desitjable si es vol mantindre una història lineal.
L'opció --no-edit indica que no es vol editar el missatge del commit de fusió
i que es manté el missatge per defecte.
Amb un canvi de base: git pull --rebase.
Aquesta opció aplica els canvis de la branca local després dels canvis de la branca remota,
de manera que es manté una història lineal.
jpuigcerver@fp:~/git_remots(main)$gitpull--rebase
Rebasing (1/1)Successfully rebased and updated refs/heads/main.jpuigcerver@fp:~/git_remots(main)$gitlga
*f8377ad-(1 second ago)Beguda-Joan Puigcerver(HEAD -> main)*735c088-(1 second ago)Més menjar-Joan Puigcerver(origin/main, origin/HEAD)*b460858-(1 second ago)Menjar-Joan Puigcerver*2036c5a-(1 second ago)Commit inicial-Joan Puigcerver