L'Ana ja té el seu remot registrat. Escriu git push origin main amb tota la il·lusió i obté això:

Username for 'https://git.exemple.cat':

Un indicatiu esperant alguna cosa que no sap gaire bé què és. I si teclegés la contrasenya amb què entra a la interfície web, és molt probable que rebés un rebuig del tipus Support for password authentication was removed.

Aquest mur atura molta gent en el seu primer contacte amb un repositori remot, i és una llàstima, perquè el problema no té res a veure amb Git: és un problema d'identitat. Registrar un URL no dona permís per escriure-hi. Algú ha de demostrar al servidor que és qui diu ser.

Aquesta lliçó resol aquest mur d'una vegada i per sempre. Veurem per què el clone d'un repositori públic no demana res i el push sí, els dos mecanismes d'autenticació que es fan servir avui —testimonis sobre HTTPS i claus SSH—, com generar una clau amb ssh-keygen, i com fer que el sistema operatiu recordi les credencials per no haver-les de teclejar quaranta vegades al dia. És la lliçó que la Carla necessita abans d'escriure la seva primera línia, perquè entra des de Windows 11 i allà el gestor de credencials funciona d'una manera diferent.

Contingut

  1. Per què el clone públic no demana res i el push
  2. Autenticació davant d'autorització
  3. HTTPS amb testimoni personal d'accés
  4. SSH: el parell de claus
  5. Generar la clau amb ssh-keygen -t ed25519
  6. Pujar la pública, provar la connexió i fer servir l'agent
  7. ~/.ssh/config: diverses identitats a la mateixa màquina
  8. HTTPS davant de SSH: taula comparativa
  9. Gestors de credencials per sistema operatiu
  10. Errors típics i com diagnosticar-los

  1. Per què el clone públic no demana res i el push

La resposta és senzilla i aclareix molta confusió: són operacions amb requisits de permís diferents.

Operació Què fa Repositori públic Repositori privat
git clone, git fetch, git pull Llegir objectes i referències Sense credencials Credencials
git push Escriure: modificar referències del servidor Credencials sempre Credencials

Un repositori públic és, per definició, llegible per qualsevol. Descarregar el codi d'un projecte obert no requereix identificar-se, igual que llegir una pàgina web no requereix compte.

Escriure és una altra història. Quan envies, li estàs demanant al servidor que modifiqui les seves referències: que refs/heads/main passi a apuntar a un altre commit. Això canvia el que tothom veurà en clonar a partir d'aquell moment. Cap servidor assenyat no permet això a un desconegut.

I hi ha un matís que sorprèn molta gent: la identitat de Git i la identitat del servidor són coses diferents.

git config user.name
git config user.email

Això que vas configurar a la lliçó 01-06 és metadada del commit: text que es grava dins de l'objecte i que apareix a git log. No autentica res. Qualsevol pot posar qualsevol nom i qualsevol correu als seus commits; Git no ho verifica.

L'autenticació passa en una altra capa: al transport, quan el teu Git parla amb el servidor. Són dues identitats independents que convé no barrejar:

user.name / user.email Credencials d'accés
On viu A la configuració de Git Al gestor de credencials o a ~/.ssh/
Per a què serveix Signar l'autoria del commit Demostrar qui ets davant del servidor
Ho verifica algú No Sí, el servidor, a cada connexió
Quan intervé En fer git commit En fer fetch, pull o push

(Existeix una manera de vincular totes dues coses de debò, signant els commits criptogràficament. És un tema de seguretat i es tracta a la lliçó 08-05.)

  1. Autenticació davant d'autorització

Dues paraules que es confonen cada dia i que produeixen errors molt diferents:

  • Autenticació: qui ets. Demostrar la teva identitat davant del servidor.
  • Autorització: què pots fer. Els permisos que aquesta identitat té sobre aquell repositori concret.

Pots estar perfectament autenticat i tot i així rebre un rebuig:

remote: Permission to equip/gestor-tasques.git denied to carla.
fatal: unable to access 'https://git.exemple.cat/equip/gestor-tasques.git/': The requested URL returned error: 403

Fixa't en el missatge: el servidor sap que ets la Carla. L'autenticació ha funcionat. El que falla és l'autorització: a la Carla no li han donat permís d'escriptura en aquell repositori, o el seu testimoni no té l'àmbit necessari.

Distingir els dos casos estalvia molt de temps:

Símptoma Capa que falla Què revisar
Permission denied (publickey) Autenticació (SSH) La clau: si existeix, si està carregada, si està pujada al servidor
Authentication failed (HTTPS) Autenticació El testimoni: si és vàlid, si ha caducat, si està ben desat
403 Forbidden, Permission to … denied to <usuari> Autorització Els permisos del teu compte al repositori; els àmbits del testimoni
Repository not found Totes dues, ambiguament Moltes plataformes retornen això per a repositoris privats als quals no tens accés, per no revelar que existeixen

Aquest darrer cas és especialment traïdor: Repository not found no significa necessàriament que hagis escrit malament l'URL. Pot voler dir «existeix, però per a tu no».

  1. HTTPS amb testimoni personal d'accés

Què és un PAT i per què va substituir la contrasenya

Un testimoni personal d'accés (Personal Access Token, PAT) és una cadena llarga generada per la plataforma que funciona com una contrasenya per a un ús concret. Té un aspecte semblant a aquest (fictici, evidentment):

glpat-7fK2mQx9RtVb3Ln8ZwYc

Durant anys, l'autenticació per HTTPS es feia amb l'usuari i la contrasenya del compte. GitHub va retirar aquesta possibilitat l'agost de 2021 i la resta de plataformes va seguir el mateix camí. Les raons són sòlides:

  • Àmbit limitat. La teva contrasenya obre tot el compte: repositoris, ajustos, facturació, esborrat. Un testimoni pot donar només lectura d'un repositori concret.
  • Revocable individualment. Si un testimoni es filtra, l'elimines i només es trenca el que el feia servir. Canviar la contrasenya t'obliga a reconfigurar-ho tot.
  • Compatible amb doble factor. Si el teu compte té segon factor, no hi ha manera d'introduir-lo en un indicatiu de Git. El testimoni resol aquest carreró sense sortida.
  • Caducitat. Un testimoni pot expirar en 30, 60 o 90 dies; una contrasenya viu fins que algú se'n recorda de canviar-la.
  • Auditable. La plataforma registra quin testimoni ha fet què i quan es va fer servir per darrera vegada.

Com es crea i amb quins àmbits

El procediment concret varia per plataforma, però l'esquema és sempre el mateix: ajustos del compte → testimonis d'accés → crear → triar nom, caducitat i àmbits.

Els àmbits són la part important. Concedeix el mínim imprescindible:

Necessitat Àmbit típic Què permet
Clonar i fer fetch de repositoris privats read_repository / repo:read Només lectura
Fer push write_repository / repo Lectura i escriptura de codi
Només un repositori concret Testimoni amb àmbit de projecte Accés acotat a aquell repositori
Integració contínua El mínim que necessiti la tasca Vegeu el mòdul 7

El que gairebé mai no necessites: àmbits d'administració, de gestió d'usuaris, d'esborrat de repositoris o d'accés als ajustos de l'organització. Un testimoni de desplegament que només ha de clonar no hauria de poder esborrar res.

Un consell operatiu: crea un testimoni per màquina, no un que comparteixis entre el teu portàtil, l'ordinador de casa i el servidor d'integració contínua. Si perds el portàtil, revoques aquell testimoni i la resta continua funcionant.

Com es fa servir

El testimoni s'introdueix al lloc de la contrasenya:

git push origin main
Username for 'https://git.exemple.cat': ana.ferrer
Password for 'https://[email protected]':

En aquest segon indicatiu hi va el testimoni, no la contrasenya del compte. Com que no es veu mentre s'escriu, és còmode enganxar-lo des del porta-retalls.

El que no has de fer mai és incrustar-lo a l'URL:

# MALAMENT: no facis això
git remote add origin https://ana:[email protected]/equip/gestor-tasques.git

Aquest testimoni acaba escrit en text pla a .git/config, apareix a l'historial del teu shell, es cola en captures de pantalla i surt en qualsevol git remote -v que executis davant d'algú. Per a això existeixen els gestors de credencials de l'apartat 9.

  1. SSH: el parell de claus

L'alternativa a HTTPS és SSH, i es basa en un concepte diferent: en lloc d'un secret compartit, es fa servir un parell de claus asimètriques.

  • La clau privada (~/.ssh/id_ed25519) es queda a la teva màquina i no en surt mai. És l'equivalent a la teva clau física.
  • La clau pública (~/.ssh/id_ed25519.pub) es puja al servidor. És l'equivalent al pany: es pot repartir sense risc.

La propietat matemàtica que ho fa funcionar és que el que es verifica amb la pública només ho ha pogut produir la privada, i la privada no es pot deduir de la pública.

sequenceDiagram
    participant C as Portàtil de la Carla
    participant S as git.exemple.cat

    C->>S: Vull connectar-me com a usuari "git"
    S->>C: Repte: signa aquesta dada aleatòria
    Note over C: Signa amb la clau PRIVADA<br/>(que no surt mai del disc)
    C->>S: Aquí tens la signatura
    Note over S: Verifica amb la clau PÚBLICA<br/>que la Carla va pujar abans
    S->>C: Verificada. Accés concedit

L'avantatge sobre el testimoni és evident: el secret no viatja mai per la xarxa. Ni tan sols xifrat. L'única cosa que es transmet és una signatura d'una dada aleatòria diferent a cada connexió, inútil per a un atacant que la capturi.

Els tipus de clau

Tipus Estat Comentari
Ed25519 Recomanat Modern, ràpid, claus curtes (68 caràcters), seguretat excel·lent
RSA 4096 Acceptable Segur, però claus llargues i més lent; útil en sistemes antics que no admeten Ed25519
RSA 2048 Desaconsellat Ja no es considera suficient
ECDSA Desaconsellat Dubtes sobre les corbes estàndard; Ed25519 el supera en tot
DSA Prohibit Obsolet i eliminat d'OpenSSH

Fes servir Ed25519 llevat que et trobis amb un servidor antic que el rebutgi, cas en què rsa amb 4096 bits.

  1. Generar la clau amb ssh-keygen -t ed25519

La Carla, des del seu Windows 11, obre el Git Bash (que va instal·lar a la lliçó 01-02 i que porta totes les eines d'OpenSSH). Les ordres són idèntiques a Linux, macOS i Git Bash:

ssh-keygen -t ed25519 -C "[email protected]"

Desglossament de les opcions:

  • -t ed25519: el tipus de clau. És l'argument important.
  • -C "…": un comentari que s'afegeix al final de la clau pública. Serveix per identificar-la a la llista del servidor quan tinguis quatre claus de quatre màquines. Pot ser el correu, però encara és millor una cosa com ara "carla-portatil-windows", perquè el que vols saber és de quina màquina és aquella clau.

El diàleg:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/c/Users/carla/.ssh/id_ed25519):

Prem Retorn per acceptar la ruta per defecte. Canvia-la només si tindràs diverses claus, cas que veurem a l'apartat 7.

Enter passphrase (empty for no passphrase):
Enter same passphrase again:

Aquí cal aturar-se. La passphrase xifra la clau privada al disc. Si algú et roba el portàtil o copia el fitxer, sense ella la clau no serveix de res.

Amb passphrase Sense passphrase
Seguretat si et roben el fitxer La clau és inútil sense la frase Accés immediat als teus repositoris
Comoditat diària Es teclega una vegada per sessió (amb ssh-agent) No es teclegen mai
Ús en automatització sense supervisió Complicat És l'habitual, amb la clau molt restringida
Recomanació Posa-la sempre en màquines personals Només en claus de desplegament de només lectura

Posa-la. Amb ssh-agent, el cost real és teclejar-la una vegada en engegar l'ordinador.

El resultat:

Your identification has been saved in /c/Users/carla/.ssh/id_ed25519
Your public key has been saved in /c/Users/carla/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:9xK2mQ7RtVb3Ln8ZwYcF4dJ6hP1sT5uA2eB9gN0kM3o [email protected]

Dos fitxers. Vegem què contenen:

ls -l ~/.ssh/
-rw-------  1 carla  carla   464 ago  1 09:12 id_ed25519
-rw-r--r--  1 carla  carla   103 ago  1 09:12 id_ed25519.pub

Fixa't en els permisos, que són part del mecanisme de seguretat:

  • La privada és -rw------- (600): només tu la pots llegir. Si tingués permisos més oberts, OpenSSH es negaria a fer-la servir.
  • La pública és -rw-r--r-- (644): llegible per qualsevol, i no passa res.
cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK7Rt2mQx9VbLn8ZwYcF4dJ6hP1sT5uA2eB9gN0kM3o [email protected]

Tres parts: el tipus, la clau pròpiament dita i el comentari. Aquesta línia és la que es puja al servidor, i es pot publicar sense cap risc.

I la privada, amb l'advertiment obvi:

head -2 ~/.ssh/id_ed25519
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDl...

Aquest contingut no s'ensenya, no es copia i no s'envia a ningú. Mai. Ni a un company, ni a suport tècnic, ni enganxat en un xat. Si algun cop tens el dubte de quin dels dos fitxers cal pujar, la regla és infal·lible: el que acaba en .pub.

  1. Pujar la pública, provar la connexió i fer servir l'agent

Pujar la clau pública

Es copia el contingut del .pub i s'enganxa a la plataforma (ajustos del compte → claus SSH → clau nova). Per copiar-lo al porta-retalls:

# Linux (amb xclip instal·lat)
xclip -selection clipboard < ~/.ssh/id_ed25519.pub

# macOS
pbcopy < ~/.ssh/id_ed25519.pub

# Windows amb Git Bash
clip < ~/.ssh/id_ed25519.pub

Un avís freqüent: en enganxar, no hi ha de quedar cap salt de línia al mig. La clau és una sola línia llarga; si l'editor la parteix, no funcionarà.

Provar la connexió amb ssh -T

Abans d'intentar cap ordre de Git, comprova que el canal funciona:

L'opció -T significa «no vull terminal interactiu»: només estic comprovant l'autenticació.

La primera vegada apareix això:

The authenticity of host 'git.exemple.cat (192.0.2.42)' can't be established.
ED25519 key fingerprint is SHA256:p2Q9xL4mR7tVc3Nb8ZwYeF6dJ1sK5uA0eB7gN2kM9o.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

No responguis yes per inèrcia. Aquest missatge diu que el teu ordinador encara no coneix aquell servidor i et demana que confirmis que és l'autèntic. Les plataformes publiquen les seves empremtes a la documentació; compara-la abans d'acceptar. És l'única defensa contra un atac d'intermediari en aquella primera connexió.

En acceptar, l'empremta es desa a ~/.ssh/known_hosts i no ho tornarà a preguntar.

Si tot va bé:

Hi carla! You've successfully authenticated, but I do not provide shell access.

Aquest missatge és un èxit complet, encara que digui que no dona accés al shell. Això és exactament el que ha de passar: l'usuari git d'un servidor de repositoris no serveix per obrir una sessió, només per parlar Git.

ssh-agent: teclejar la passphrase una sola vegada

Amb passphrase, cada operació demanaria la frase. L'agent la desa a la memòria durant la sessió i respon per tu.

# Engegar l'agent (si no està ja en marxa)
eval "$(ssh-agent -s)"
Agent pid 5842
# Carregar la clau: demanarà la passphrase una vegada
ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/carla/.ssh/id_ed25519:
Identity added: /home/carla/.ssh/id_ed25519 ([email protected])
# Veure quines claus té carregades
ssh-add -l
256 SHA256:9xK2mQ7RtVb3Ln8ZwYcF4dJ6hP1sT5uA2eB9gN0kM3o [email protected] (ED25519)

A partir d'aquí, tots els push i pull funcionen sense teclejar res.

Cada sistema té la seva manera de deixar-ho automatitzat:

# Linux: afegir al final de ~/.bashrc o ~/.zshrc
if [ -z "$SSH_AUTH_SOCK" ]; then
  eval "$(ssh-agent -s)" > /dev/null
  ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi
# macOS: desa la passphrase al Clauer i la carrega sola
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
# macOS: i perquè es carregui a cada sessió, a ~/.ssh/config
Host *
  UseKeychain yes
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519

A Windows 11, el servei ssh-agent ve amb el sistema però arrenca desactivat. Des del PowerShell com a administrador:

Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent

I després, ja des del Git Bash:

ssh-add ~/.ssh/id_ed25519

Un detall per a la Carla: si fa servir l'ssh del Git Bash i l'agent del sistema, poden no veure's entre ells. La solució senzilla és fer servir el bloc de ~/.bashrc de més amunt, que engega un agent propi del Git Bash.

  1. ~/.ssh/config: diverses identitats a la mateixa màquina

Situació molt real, i precisament la de la Carla: a la lliçó 01-05 vam veure que treballa en dos contextos, el d'exemple.cat i el d'una altra empresa, amb correus diferents. Si a més cadascun exigeix un compte i una clau diferents, cal dir-li a SSH quina fer servir en cada cas.

Això es resol a ~/.ssh/config:

# Compte de la feina
Host git.exemple.cat
    HostName git.exemple.cat
    User git
    IdentityFile ~/.ssh/id_ed25519_feina
    IdentitiesOnly yes
    AddKeysToAgent yes

# Compte de l'altra empresa: àlies inventat
Host git-altraempresa
    HostName git.altraempresa.cat
    User git
    IdentityFile ~/.ssh/id_ed25519_altraempresa
    IdentitiesOnly yes
    AddKeysToAgent yes

Explicació de cada directiva:

Directiva Què fa
Host L'àlies que escrius a l'URL. Pot ser inventat
HostName El servidor real al qual connectar-se
User L'usuari SSH: a les plataformes de Git és gairebé sempre git
IdentityFile Quina clau privada fer servir per a aquesta destinació
IdentitiesOnly yes Fes servir només aquesta clau, no totes les que tinguis carregades
AddKeysToAgent yes Carrega la clau a l'agent al primer ús

IdentitiesOnly yes mereix un comentari, perquè evita una errada desconcertant. Sense ell, SSH ofereix totes les teves claus una rere l'altra fins que alguna funcioni; si en tens cinc, el servidor pot tallar la connexió per excés d'intents i obtindràs un Too many authentication failures que no sembla tenir res a veure amb la causa real.

El truc de l'àlies inventat és el que fa potent aquest fitxer. Fixa't en Host git-altraempresa: aquest nom no existeix a cap DNS. Però ara la Carla pot escriure:

git clone git@git-altraempresa:projectes/facturacio.git

I SSH tradueix git-altraempresa a git.altraempresa.cat amb la clau correcta. El mateix mecanisme serveix per a dos comptes a la mateixa plataforma, que és el cas clàssic de tenir un compte personal i un altre d'empresa al mateix GitHub:

Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_personal
    IdentitiesOnly yes

Host github-empresa
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_empresa
    IdentitiesOnly yes
# Repositori personal
git clone git@github-personal:carla/el-meu-blog.git

# Repositori de l'empresa
git clone git@github-empresa:exemple-sl/gestor-tasques.git

Mateix servidor real, dues identitats, sense cap ambigüitat.

I per comprovar quina clau es farà servir realment:

ssh -T -v [email protected] 2>&1 | grep -i "offering\|identity file"
debug1: identity file /home/carla/.ssh/id_ed25519_feina type 3
debug1: Offering public key: /home/carla/.ssh/id_ed25519_feina ED25519

L'opció -v (verbose) és l'eina de diagnòstic definitiva per a qualsevol problema d'SSH.

Permisos del fitxer, que també són estrictes:

chmod 600 ~/.ssh/config
chmod 700 ~/.ssh

  1. HTTPS davant de SSH: taula comparativa

Les dues opcions són vàlides i totes dues es fan servir massivament. L'elecció depèn del context:

Criteri HTTPS + testimoni SSH
Facilitat inicial Alta: enganxar un testimoni i llestos Mitjana: generar clau, pujar-la, provar
Tallafocs corporatius Excel·lent: fa servir el port 443, obert a tot arreu Problemàtica: el port 22 sol estar tancat
Ús diari Transparent amb gestor de credencials Transparent amb ssh-agent
El secret viatja per la xarxa Sí (dins del xifratge TLS) No, mai
Caducitat Sí: cal renovar el testimoni cada 30-90 dies No caduca
Granularitat de permisos Alta: àmbits per testimoni Baixa: la clau dona el que dona el teu compte
Diverses identitats Complicat: el gestor en desa una per servidor Senzill amb ~/.ssh/config
Automatització i CI Preferit: testimonis amb àmbit mínim i caducitat Possible amb claus de desplegament
Revocació Immediata des del web Immediata esborrant la clau
Repositoris públics de només lectura Ideal: sense credencials Innecessari
Darrere d'un proxy Es configura fàcilment a Git Requereix configuració addicional d'SSH

Recomanació pràctica

  • Màquina de treball diari, mateix compte sempreSSH. Es configura una vegada i s'oblida: no caduca, no es renova i no interromp.
  • Xarxa corporativa amb el port 22 tancatHTTPS + testimoni. (Algunes plataformes ofereixen SSH pel port 443 com a alternativa.)
  • Integració contínua, contenidors, servidorsTestimoni amb l'àmbit mínim i caducitat curta, o una clau de desplegament de només lectura.
  • Clonar un projecte públic per llegir-loHTTPS sense credencials.
  • Diversos comptes a la mateixa màquinaSSH amb ~/.ssh/config.

I una dada tranquil·litzadora: canviar d'una a l'altra és un set-url, com vam veure a la lliçó anterior:

# D'HTTPS a SSH
git remote set-url origin [email protected]:equip/gestor-tasques.git

# De SSH a HTTPS
git remote set-url origin https://git.exemple.cat/equip/gestor-tasques.git

No hi perds res: els commits són els mateixos, les referències són les mateixes i només canvia el camí.

  1. Gestors de credencials per sistema operatiu

Amb HTTPS queda un problema pràctic: ningú no teclejarà un testimoni de 40 caràcters a cada push. Per a això existeix credential.helper, que ja va treure el nas a la lliçó 01-06 i que ara podem entendre del tot.

Un credential helper és un programa extern al qual Git li pregunta «tens credencials per a aquest servidor?» abans de mostrar l'indicatiu, i al qual li diu «desa't aquestes» quan l'accés funciona.

sequenceDiagram
    participant G as git push
    participant H as credential.helper
    participant A as Magatzem del sistema
    participant S as Servidor

    G->>H: Credencials per a git.exemple.cat?
    H->>A: Consulta (xifrada)
    A-->>H: usuari + testimoni
    H-->>G: Aquí les tens
    G->>S: Autenticació
    S-->>G: Correcte
    Note over G,A: Si fallen, Git ho pregunta a l'usuari<br/>i demana al helper que desi les noves

El de cada sistema

Linux (Ana, Ubuntu) — libsecret

S'integra amb el clauer de l'escriptori (GNOME Keyring, KWallet), que desa els secrets xifrats i es desbloqueja amb la sessió:

sudo apt install libsecret-1-0 libsecret-1-dev

# Compilar l'ajudant que ve amb Git
sudo make --directory=/usr/share/doc/git/contrib/credential/libsecret

git config --global credential.helper \
  /usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret

En algunes distribucions ve ja compilat i n'hi ha prou d'instal·lar el paquet corresponent.

macOS (Bruno) — osxkeychain

Ve inclòs amb Git a macOS; una sola línia:

git config --global credential.helper osxkeychain

Les credencials es desen al Clauer, xifrades i visibles a l'aplicació Accés a Clauers, on es poden revisar i esborrar.

Windows 11 (Carla) — Git Credential Manager

És el cas més interessant, i per això el deixem per al final. GCM s'instal·la juntament amb Git per a Windows i queda configurat per defecte:

git config --global credential.helper manager
# Comprovar què hi ha configurat
git config --global --get credential.helper
manager

El que fa GCM va més enllà de desar una cadena:

  • Desa les credencials a l'Administrador de credencials de Windows, xifrades amb el compte d'usuari del sistema.
  • Obre una finestra de navegador per autenticar-se contra GitHub, GitLab o Azure DevOps, amb suport per a doble factor.
  • Pot generar i renovar testimonis per si mateix, de manera que la Carla no n'ha de crear cap a mà.
  • És multiplataforma: existeix també per a Linux i macOS, encara que en aquests sistemes els natius solen ser suficients.

Per a la Carla, això significa que el seu primer git clone d'un repositori privat obrirà una finestra del navegador, ella hi entrarà amb el seu compte i el seu segon factor, i a partir d'aquí no tornarà a veure cap indicatiu. És, amb diferència, l'experiència més còmoda de les tres.

Si vol comprovar què hi ha desat, ho pot obrir des del Git Bash:

# Obre l'Administrador de credencials de Windows
control /name Microsoft.CredentialManager

Les entrades de Git apareixen a la secció «Credencials genèriques» amb el prefix git:.

Resum i store, el que no has de fer servir

Ajudant Sistema On desa Xifrat Recomanació
manager Windows (i multiplataforma) Administrador de credencials de Windows L'opció a Windows
osxkeychain macOS Clauer del sistema L'opció a macOS
libsecret Linux Clauer de l'escriptori L'opció a Linux
cache Qualsevol Memòria RAM, temporalment No s'aplica: no toca el disc Acceptable: segur però oblidadís
store Qualsevol ~/.git-credentials, text pla NO Evita'l

Per què store desa en text pla i quan (no) fer-lo servir

És temptador pel que és de fàcil:

git config --global credential.helper store

I funciona a la primera. El problema es veu en mirar el fitxer que crea:

cat ~/.git-credentials
https://ana.ferrer:[email protected]

El teu testimoni, llegible, en un fitxer de la teva carpeta personal. Sense xifrar, sense contrasenya mestra, sense caducitat. Els permisos són 600, cosa que protegeix d'altres usuaris de la mateixa màquina, però no de:

  • Qualsevol programa que s'executi amb el teu usuari, inclosa una dependència maliciosa del teu projecte.
  • Una còpia de seguretat de la teva carpeta personal que acabi en un disc extern o al núvol.
  • Algú que engegui l'ordinador des d'un USB o extregui el disc.
  • Un fitxer de configuració sincronitzat per error entre màquines.

Quan no fer-lo servir: al teu portàtil, al teu ordinador de sobretaula, en qualsevol màquina amb accés a repositoris que importin.

Quan podria tenir sentit: en un contenidor efímer o una màquina virtual descartable, aïllada, amb un testimoni de només lectura i caducitat d'hores, on no hi ha cap clauer disponible i el cicle de vida de la màquina és més curt que el del testimoni. Fins i tot allà, gairebé sempre hi ha una opció millor.

L'alternativa raonable quan no hi ha clauer és cache, que manté les credencials a la memòria durant un temps limitat:

git config --global credential.helper 'cache --timeout=3600'

Una hora sense tornar a teclejar, i res tocant el disc. En apagar, desapareix.

Tot el relatiu a la gestió de secrets, la signatura de commits i el tractament de credencials filtrades a l'historial es desenvolupa a la lliçó 08-05. Aquí ens hem ocupat del que és operatiu: poder treballar còmodament sense deixar secrets escampats.

  1. Errors típics i com diagnosticar-los

Permission denied (publickey)

[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

És l'error d'SSH més habitual. Significa: «El servidor no ha acceptat cap de les claus que li has ofert.» Les causes, en ordre de freqüència:

# 1. Existeix la clau?
ls -l ~/.ssh/
# 2. Està carregada a l'agent?
ssh-add -l

Si respon Could not open a connection to your authentication agent, l'agent no està en marxa:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

Si respon The agent has no identities, està en marxa però buit: falta l'ssh-add.

# 3. La clau pública pujada al servidor és la mateixa que tens?
ssh-keygen -lf ~/.ssh/id_ed25519.pub
256 SHA256:9xK2mQ7RtVb3Ln8ZwYcF4dJ6hP1sT5uA2eB9gN0kM3o [email protected] (ED25519)

Compara aquesta empremta amb la que mostra la plataforma a la llista de claus. Si no coincideix, en vas pujar una altra.

# 4. Els permisos són correctes?
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

OpenSSH ignora en silenci les claus privades amb permisos massa oberts, cosa que produeix aquest error sense cap pista.

# 5. El diagnòstic definitiu
ssh -vT [email protected]

A la sortida veuràs quines claus ofereix (Offering public key:) i com respon el servidor. És la manera més ràpida de descobrir que estàs oferint la clau equivocada.

Host key verification failed

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Significa que la clau del servidor no coincideix amb la que tenies desada a ~/.ssh/known_hosts. Hi ha dues explicacions possibles:

  1. Legítima: el servidor s'ha reinstal·lat, s'ha migrat o la plataforma ha rotat les seves claus (passa de tant en tant i sempre s'anuncia públicament).
  2. Atac d'intermediari: algú s'està fent passar pel servidor.

No esborris l'entrada sense comprovar-ho. El procediment correcte:

# 1. Veure quina empremta està presentant el servidor ara
ssh-keyscan git.exemple.cat 2>/dev/null | ssh-keygen -lf -
256 SHA256:p2Q9xL4mR7tVc3Nb8ZwYeF6dJ1sK5uA0eB7gN2kM9o git.exemple.cat (ED25519)
# 2. Comparar amb l'empremta oficial publicada per la plataforma.
#    Si i només si coincideix, eliminar l'entrada antiga:
ssh-keygen -R git.exemple.cat

# 3. Reconnectar i acceptar la nova
ssh -T [email protected]

La variant suau del mateix avís —The authenticity of host … can't be established— és la primera connexió: encara no hi ha res desat. També allà convé comparar l'empremta abans d'acceptar.

Altres errors freqüents

Missatge Causa habitual Solució
Support for password authentication was removed Estàs fent servir la contrasenya del compte Genera un testimoni i fes-lo servir en lloc seu
Authentication failed for 'https://…' Testimoni caducat, revocat o mal desat Esborra la credencial del gestor i torna't a autenticar
403 Forbidden / Permission to … denied Autorització, no autenticació Revisa permisos al repositori i àmbits del testimoni
Repository not found Repositori privat sense accés, o URL erroni Verifica l'URL i els teus permisos
Connection timed out (port 22) Tallafocs bloquejant SSH Fes servir HTTPS, o SSH pel port 443 si la plataforma l'ofereix
Too many authentication failures SSH ofereix massa claus IdentitiesOnly yes a ~/.ssh/config
Load key … bad permissions Permisos massa oberts a la privada chmod 600 ~/.ssh/id_ed25519

I una ordre que resol el «no sé quina credencial està fent servir Git»:

GIT_TRACE=1 GIT_CURL_VERBOSE=1 git fetch origin 2>&1 | head -30

Mostra el procés complet, inclòs quin ajudant de credencials s'invoca. Fes-lo servir només per depurar i no comparteixis la seva sortida sense revisar-la, perquè pot incloure capçaleres sensibles.

Errors Habituals i Consells

Error 1: pujar la clau privada en lloc de la pública. Passa més del que sembla. La regla és simple: es puja el fitxer que acaba en .pub. Si has pujat la privada per error, esborra-la del servidor, elimina el parell sencer del teu disc i genera'n un de nou: aquella clau està compromesa per sempre.

Error 2: incrustar el testimoni a l'URL del remot. Acaba a .git/config, a l'historial del shell i en qualsevol captura de pantalla. Fes servir un gestor de credencials.

Error 3: crear la clau sense passphrase «per anar de pressa». El robatori del portàtil passa de ser un problema de maquinari a ser un problema d'accés a tots els teus repositoris. Amb ssh-agent, la passphrase es teclega una vegada per sessió.

Error 4: confondre user.email amb la identitat d'accés. Canviar user.email no arregla cap problema d'autenticació: només canvia el text que apareix als commits. Són capes diferents.

Error 5: acceptar l'empremta del servidor sense mirar-la. Aquest indicatiu de la primera connexió és l'única oportunitat de detectar una suplantació. Les plataformes publiquen les seves empremtes; comparar-les costa deu segons.

Error 6: fer servir el mateix testimoni en cinc màquines. Quan s'hagi de revocar, es trencaran les cinc alhora i no sabràs quina es va filtrar. Un testimoni per màquina i per propòsit.

Error 7: fer servir credential.helper store per defecte. Deixa el testimoni en text pla a la teva carpeta personal. Fes servir el gestor natiu del teu sistema, o cache si no n'hi ha cap de disponible.

Consell 1: prova sempre amb ssh -T abans de culpar Git. Si ssh -T git@servidor funciona, el problema no és a SSH. Si no funciona, ssh -vT et diu exactament en quin pas falla.

Consell 2: posa un comentari útil a la clau. -C "carla-portatil-windows" és infinitament més pràctic que el correu quan d'aquí a un any vegis quatre claus a la llista del servidor i hagis de decidir quina revocar.

Consell 3: apunta la caducitat dels teus testimonis. Un testimoni que expira un dilluns al matí genera mitja hora de desconcert. Posa't un recordatori uns dies abans.

Consell 4: IdentitiesOnly yes sempre que tinguis més d'una clau. Evita el Too many authentication failures, que és dels errors més difícils de relacionar amb la seva causa.

Consell 5: per a automatització, àmbit mínim i caducitat curta. Un testimoni d'integració contínua que només ha de clonar no necessita permís d'escriptura ni d'administració.

Exercicis

Exercici 1: generar i auditar un parell de claus

Sense pujar res a cap servidor:

  1. Genera un parell Ed25519 en una ruta específica: ~/.ssh/practica_curs, amb un comentari descriptiu.
  2. Mostra els permisos dels dos fitxers i explica per què són diferents.
  3. Mostra l'empremta de la clau pública.
  4. Carrega-la a ssh-agent i verifica que apareix llistada.
  5. Comprova que l'empremta de la clau privada i la de la pública coincideixen. Explica per què.
  6. Descarrega-la de l'agent i elimina els fitxers.

Exercici 2: configurar dues identitats

La Carla necessita treballar amb dos comptes: el de l'equip (git.exemple.cat) i el d'una altra empresa (git.altraempresa.cat).

  1. Escriu el ~/.ssh/config complet per a tots dos, amb claus separades.
  2. Explica què fa cada directiva.
  3. Escriu l'URL de clonatge que faria servir per a cada repositori.
  4. Indica l'ordre que li permetria comprovar quina clau concreta s'ofereix a cada servidor.
  5. Explica què passaria si ometés IdentitiesOnly yes i tingués sis claus carregades.

Exercici 3: diagnòstic

Per a cadascun d'aquests missatges, indica: (a) si l'errada és d'autenticació o d'autorització, (b) les dues causes més probables i (c) l'ordre o comprovació amb què començaries.

  1. [email protected]: Permission denied (publickey).
  2. remote: Permission to equip/gestor-tasques.git denied to carla.
  3. remote: Support for password authentication was removed.
  4. WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
  5. ssh: connect to host git.exemple.cat port 22: Connection timed out

Solucions

Solució 1:

# 1. Generar amb ruta i comentari
ssh-keygen -t ed25519 -f ~/.ssh/practica_curs -C "practica-curs-git"
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/carla/.ssh/practica_curs
Your public key has been saved in /home/carla/.ssh/practica_curs.pub
The key fingerprint is:
SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curs-git

L'opció -f fixa la ruta i evita el diàleg d'«on desar».

# 2. Permisos
ls -l ~/.ssh/practica_curs*
-rw------- 1 carla carla 464 ago  1 10:22 /home/carla/.ssh/practica_curs
-rw-r--r-- 1 carla carla 103 ago  1 10:22 /home/carla/.ssh/practica_curs.pub

La privada és 600: només el seu propietari la pot llegir, i OpenSSH es nega a fer-la servir si tingués permisos més laxos, perquè qualsevol altre usuari del sistema la podria copiar. La pública és 644 perquè està dissenyada per repartir-se: no revela res explotable.

# 3. Empremta de la pública
ssh-keygen -lf ~/.ssh/practica_curs.pub
256 SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curs-git (ED25519)
# 4. Carregar i llistar
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/practica_curs
ssh-add -l
Agent pid 6120
Enter passphrase for /home/carla/.ssh/practica_curs:
Identity added: /home/carla/.ssh/practica_curs (practica-curs-git)
256 SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curs-git (ED25519)
# 5. Les dues empremtes
ssh-keygen -lf ~/.ssh/practica_curs
ssh-keygen -lf ~/.ssh/practica_curs.pub
256 SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curs-git (ED25519)
256 SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curs-git (ED25519)

Idèntiques, i no és casualitat. L'empremta és un hash de la clau pública, i la pública es pot derivar de la privada (el contrari, no). Quan ssh-keygen -lf rep una clau privada, n'extreu la pública i en calcula l'empremta. Per això l'empremta serveix per emparellar sense ambigüitat quina privada del teu disc correspon a quina pública pujada al servidor: és exactament la comprovació de l'apartat 10.

# 6. Neteja
ssh-add -d ~/.ssh/practica_curs
rm ~/.ssh/practica_curs ~/.ssh/practica_curs.pub

Solució 2:

# Primer, les dues claus
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_feina -C "carla-feina-exemple"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_altraempresa -C "carla-altraempresa"

1. El fitxer ~/.ssh/config:

# Identitat de l'equip de gestor-tasques
Host git.exemple.cat
    HostName git.exemple.cat
    User git
    IdentityFile ~/.ssh/id_ed25519_feina
    IdentitiesOnly yes
    AddKeysToAgent yes

# Identitat de l'altra empresa (àlies inventat)
Host git-altraempresa
    HostName git.altraempresa.cat
    User git
    IdentityFile ~/.ssh/id_ed25519_altraempresa
    IdentitiesOnly yes
    AddKeysToAgent yes
chmod 600 ~/.ssh/config

2. Què fa cada directiva:

  • Host: el nom que la Carla escriu a l'URL. Al primer bloc coincideix amb el servidor real; al segon és un àlies inventat que no existeix a cap DNS.
  • HostName: el servidor real al qual cal connectar-se. És el que resol l'àlies.
  • User git: l'usuari SSH. A les plataformes de repositoris és sempre git; l'usuari real es dedueix de la clau que presentes.
  • IdentityFile: quina clau privada fer servir amb aquesta destinació.
  • IdentitiesOnly yes: fer servir només aquesta clau, sense oferir les altres.
  • AddKeysToAgent yes: carregar-la a l'agent al primer ús, per no repetir la passphrase.

3. Els URL de clonatge:

# Repositori de l'equip
git clone [email protected]:equip/gestor-tasques.git

# Repositori de l'altra empresa: es fa servir l'ÀLIES
git clone git@git-altraempresa:projectes/facturacio.git

4. Comprovar quina clau s'ofereix:

ssh -T -v [email protected] 2>&1 | grep "Offering public key"
debug1: Offering public key: /home/carla/.ssh/id_ed25519_feina ED25519
ssh -T -v git@git-altraempresa 2>&1 | grep "Offering public key"
debug1: Offering public key: /home/carla/.ssh/id_ed25519_altraempresa ED25519

Cada destinació rep exactament una clau, la seva.

5. Sense IdentitiesOnly yes: SSH oferiria totes les claus carregades a l'agent, una per una, en un ordre que no controles. Amb sis claus i un servidor amb el MaxAuthTries a 6 (el valor habitual), és molt probable que exhaureixi els intents abans d'arribar a la correcta:

Received disconnect from 192.0.2.42 port 22:2: Too many authentication failures

Un error especialment traïdor, perquè la clau correcta existeix i està carregada: simplement no li ha donat temps de provar-la. A més, oferir totes les teves claus a qualsevol servidor amb qui parlis és una fuita d'informació innecessària: li reveles quantes identitats tens.

Solució 3:

1. Permission denied (publickey)

  • (a) Autenticació. El servidor no ha acceptat cap clau: ni tan sols sap qui ets.
  • (b) La clau no està carregada a l'agent, o la que tens al disc no és la que està pujada al servidor. Menys freqüent però molt desconcertant: permisos massa oberts a la privada, que fan que OpenSSH la ignori en silenci.
  • (c) ssh-add -l per veure què hi ha carregat i, si això no aclareix res, ssh -vT [email protected] per veure quina clau s'ofereix i com respon el servidor.

2. Permission to equip/gestor-tasques.git denied to carla

  • (a) Autorització. El missatge anomena la Carla, així que l'autenticació ha funcionat perfectament.
  • (b) El seu compte no té permís d'escriptura en aquell repositori, o —si va per HTTPS amb testimoni— el testimoni no té l'àmbit d'escriptura.
  • (c) Revisar els permisos del compte a la configuració del repositori i els àmbits del testimoni a la plataforma. No hi ha cap ordre de Git que arregli això: és un canvi al servidor.

3. Support for password authentication was removed

  • (a) Autenticació. S'està enviant un mètode que el servidor ja no admet.
  • (b) S'ha teclejat la contrasenya del compte en lloc d'un testimoni; o hi ha una credencial antiga desada al gestor, amb la contrasenya d'abans de la migració.
  • (c) Generar un testimoni amb l'àmbit necessari i, molt important, esborrar la credencial desada abans de tornar-ho a provar, o el gestor tornarà a enviar la vella:
# Eliminar la credencial emmagatzemada per a aquell servidor
printf "protocol=https\nhost=git.exemple.cat\n\n" | git credential reject

4. REMOTE HOST IDENTIFICATION HAS CHANGED!

  • (a) Autenticació, però en el sentit invers: és el servidor qui no aconsegueix demostrar la seva identitat davant teu.
  • (b) El servidor s'ha reinstal·lat o la plataforma ha rotat les seves claus (el normal); o algú està interceptant la connexió (el greu).
  • (c) Obtenir l'empremta actual i comparar-la amb la publicada oficialment abans de tocar res:
ssh-keyscan git.exemple.cat 2>/dev/null | ssh-keygen -lf -

Només si coincideix amb l'oficial: ssh-keygen -R git.exemple.cat i reconnectar.

5. connect to host … port 22: Connection timed out

  • (a) Cap de les dues: és un problema de xarxa. La connexió no arriba a establir-se, així que no hi ha ni autenticació ni autorització.
  • (b) Un tallafocs corporatiu amb el port 22 tancat (el més habitual amb diferència), o el servidor caigut.
  • (c) Comprovar la connectivitat i, si és el tallafocs, canviar de via:
# Arriba res al port 22?
nc -zv git.exemple.cat 22

# Solució pràctica: passar a HTTPS
git remote set-url origin https://git.exemple.cat/equip/gestor-tasques.git

Algunes plataformes ofereixen a més SSH pel port 443, que travessa aquests tallafocs:

Host git.exemple.cat
    HostName ssh.git.exemple.cat
    Port 443
    User git

Conclusió

Amb aquesta lliçó l'equip pot per fi parlar amb el servidor. L'essencial:

  • Llegir un repositori públic no requereix credencials; escriure sempre sí, perquè push modifica les referències del servidor.
  • user.name i user.email no autentiquen res: són metadades del commit. La identitat d'accés viu en una altra capa.
  • Autenticació (qui ets) i autorització (què pots fer) són diferents. Permission denied (publickey) és el primer; 403 Forbidden és el segon. Distingir-les dirigeix el diagnòstic.
  • HTTPS s'autentica amb un testimoni personal d'accés, que va substituir la contrasenya per ser d'àmbit limitat, revocable, caducable, auditable i compatible amb doble factor. Concedeix sempre l'àmbit mínim i fes servir un testimoni per màquina.
  • SSH s'autentica amb un parell de claus: la privada no surt mai del teu disc, la pública es puja al servidor. Genera amb ssh-keygen -t ed25519 -C "descripció", posa-hi passphrase, puja el fitxer .pub, prova amb ssh -T i fes servir ssh-agent per teclejar-la una sola vegada.
  • ~/.ssh/config resol el cas de diverses identitats, fins i tot dos comptes al mateix servidor, mitjançant àlies inventats. IdentitiesOnly yes evita el Too many authentication failures.
  • HTTPS davant de SSH: HTTPS guanya en tallafocs corporatius i en granularitat de permisos; SSH guanya en comoditat diària, en no caducar i en manejar diverses identitats. Canviar d'un a l'altre és un git remote set-url.
  • Cada sistema té el seu gestor de credencials: libsecret a Linux, osxkeychain a macOS i Git Credential Manager a Windows, que a més obre el navegador i gestiona els testimonis per tu: el camí de la Carla.
  • credential.helper store desa el testimoni en text pla a ~/.git-credentials. Evita'l en màquines reals; si no hi ha clauer, cache amb temps d'espera és millor opció.
  • Per a la resta —signatura de commits, gestió de secrets, credencials filtrades a l'historial— la lliçó 08-05.

El que ve

L'Ana, en Bruno i la Carla ja es poden autenticar. El canal està obert en els dos sentits i, per primera vegada al curs, els objectes poden viatjar d'un .git/ a un altre.

A la lliçó 04-04: Obtenint i Baixant Canvis comencem a fer-lo servir en el sentit de la recepció, i ataquem de front la confusió més estesa de Git: la diferència entre git fetch i git pull. Veurem per què fetch no toca mai el teu directori de treball, què és FETCH_HEAD, com inspeccionar el que ha arribat abans d'integrar-ho, i les diferents maneres de git pull. I per fi la Carla clona gestor-tasques i es posa al dia amb la feina dels seus companys.

Dominant Git: De Principiant a Avançat

Mòdul 1: Introducció a Git

Mòdul 2: Operacions Bàsiques de Git

Mòdul 3: Branques i Fusió

Mòdul 4: Treballant amb Repositoris Remots

Mòdul 5: Operacions Avançades de Git

Mòdul 6: Eines i Tècniques de Git

Mòdul 7: Estratègies de Col·laboració i Flux de Treball

Mòdul 8: Bones Pràctiques i Consells de Git

Mòdul 9: Resolució de Problemes i Depuració

Mòdul 10: Git al Món Real

© Copyright 2026. Tots els drets reservats