Menu

Perché Git è indispensabile, GitHub o GitLab, e come funzionano le chiavi

14 min di lettura Manuel

C'è una domanda che fa chi comincia a lavorare in un team, e la risposta che riceve quasi sempre è falsa: "a cosa serve Git?"

La risposta che si sente è "per salvare le versioni". È vera ma è inutile, come dire che serve Unix per aprire i file. Il motivo reale è un altro, e l'ha capito per primo chi lavorava in gruppi grandi: senza Git non sai chi ha cambiato che cosa, quando, e perché.

Questo articolo copre tre cose che vanno together: perché il version control è indispensabile, la differenza fra Git e le piattaforme che lo ospitano, e come funzionano le chiavi pubbliche e private. Più un po' di storia, perché anche lì le date contano e si sbaglia facile.

Perché Git è indispensabile

Tre ragioni, in ordine di importanza. La prima è quella che ti salva il lavoro, la terza è quella che ti rende bravo.

1. Il ripristino diventa una domanda, non un dramma

Il caso concreto: un rilascio va storto in produzione. Che cosa fa il team con Git? Torna alla versione di ieri con un comando e legge che cosa è cambiato fra le due.

Senza version control, la stessa domanda richiede di cercare una copia vecchia su un hard disk, sperando che qualcuno l'avesse conservata. La differenza fra le due situazioni non è il tempo che si risparmia: è che una è una procedura e l'altra è un evento.

E l'errore non è un evento raro. Un file modificato mentre si è dentro una macchina in produzione, una modifica non ancora finita quando serve rilanciare, un comando che sovrascrive un file di configurazione. Sono tutti eventi che capitano, e ognuno richiede un recupero.

2. Il contesto viaggia con il codice

Una delle conseguenze meno ovvie di Git è che i messaggi di commit raccontano il perché. Il codice dice che cosa è cambiato, il messaggio dice perché è cambiato.

Quando fra sei mesi qualcuno leggerà quella riga e penserà "ma perché -era fatta così?", la risposta sarà nella cronologia. Senza Git quel perché si perde al primo refactor, al primo freelancer che se ne va, al primo riassunto di dieci righe. Nelle organizzazioni grandi questo è la differenza fra un repository che si mantiene da solo e uno in cui ogni modifica richiede di chiedere a qualcuno.

3. Il lavoro non lineare diventa possibile

Questo è il motivo tecnico, ed è quello che rende Git diverso da tutto ciò che c'era prima.

In Git un branch è solo un riferimento a un commit. Crearlo costa niente. Il file che lo contiene è una riga di testo. Questo significa che puoi avere cento versioni diverse del codice sul tuo computer senza costo e senza conflitti, e che puoi passare da una all'altra in microsecondi.

Guarda il costo del concetto equivalente prima di Git:

# CON GIT: il branch è un file di testo, si crea in una frazione di secondo
git checkout -b correzione-pagamento

# SENZA GIT: il branch è una COPIA DELLA CARTELLA
cp -r /srv/progetto /srv/progetto-pagamento-bello
# e da quel momento i due sono due progetti diversi, e devi ricordarti
# di sincronizzarli a mano, per sempre

Il motivo per cui Git è nato è proprio questo, e lo racconto nella sezione sulla storia: Linus Torvalds serviva qualcosa che facesse questo in modo veloce, e nessuno strumento libero lo faceva.

Quello che Git non è

Vale la pena dirlo, perché le confusioni costano tempo.

  • Non è un backup. Il repository è sulla tua macchina. Se la perdi, perdi tutto, e nessun server lo sa. Il backup è un'altra cosa, e va configurata a parte.

  • Non è una copia del progetto. Un commit è uno snapshot dei file tracciati più il resto.

  • Non protegge da un attaccante che ha accesso al tuo account. Se il tuo token è compromesso, l'attaccante può scrivere sulla cronologia con le tue credenziali. Il firma (vedi sotto) è la difesa, non il fatto che il profilo "era privato".

GitHub o GitLab: la differenza che nessuno vi spiega

Il primo malinteso è già nella domanda, quindi va sciolto per primo.

Git è il programma. GitHub e GitLab sono servizi che ospitano repositori Git.

Sono cose diverse, come SQLite e Dropbox. Puoi usare Git senza mai vedere GitHub, e puoi ospitare i tuoi repository su un server tuo senza nessuno dei due. Tutti i siti che usano Git — GitHub, GitLab, Bitbucket, Codeberg, SourceForge — parlano lo stesso protocollo e usano lo stesso programma lato tuo.

Questo significa una cosa pratica importantissima: il repository non appartiene alla piattaforma. Il tuo codice è tuo, e lo porti dove vuoi con un git clone. Nessuna piattaforma ha un potere sul tuo lavoro che non sia quello legale di chi ospita il servizio.

Le differenze vere sono altre.

GitHubGitLab
Nato2008
Modellopiattaforma cloud, SaaS
Puoi installarlo tusolo GitHub Enterprise
Edizioni gratuiterepository illimitati, funzioni base
Progettoopen source, con licenza propria
Ideale perospitare codice, portfolio, collaborazione veloce

Le due righe in grassetto nella tabella sono le due che contano, e sono la vera risposta alla domanda.

GitLab è più facile da installare da solo. Non è un servizio che si possa "prendere in giro" in un'ora: è un insieme di componenti che parlano fra loro. Ma è progettato per quello, e l'edizione gratuita ha le funzioni che servono alla maggior parte dei team.

Il codice di GitHub è aperto ma la piattaforma no. Il sito è proprietario, e dal 2018 è di Microsoft. Su GitLab la Community Edition ha licenza MIT, e l'Enterprise è source-available: leggi il codice ma non puoi ridistribuirlo. La differenza è sottile e va detta con precisione, perché "GitLab è open source" è vero solo per una parte.

Una cosa da sapere, che nessuno dei due mette in evidenza: GitHub è diventato enorme. Ha superato il miliardo di repository, e nel 2018 ha subito il terzo attacco DDoS più grande della storia, con 1,35 terabit al secondo di traffico in ingresso. Il nome del repository numero miliardario dice da solo il resto.

La scelta pratica. Per un progetto personale o un team piccolo, GitHub e basta, e non per il gusto dell'ecosistema ma perché è dove sono le persone e gli strumenti. Per un'azienda che non può mandare il proprio codice fuori dai propri server, GitLab self-hosted è l'unica delle due opzioni serie. Non sono in competizione: sono due trade-off.

Le chiavi pubbliche e private

Qui c'è la parte che smonta il malinteso più diffuso, e che vale la pena fare bene perché è il cuore dell'autenticazione.

Il problema che risolvono

La crittografia simmetrica è antica e ha un solo difetto: le due parti devono condividere il segreto prima, e portarglielo in modo che nessuno lo legga è esattamente il problema che si voleva risolvere.

Il 1976 Whitfield Diffie e Martin Hellman propongono l'idea che cambia tutto: due persone che non si sono mai viste possono stabilire un segreto condiviso senza trasmettere il segreto.

Il meccanismo, in concreto

Chiavi pubbliche e private sono legate da una relazione matematica. Il trucco è che la relazione è facile in un senso e impossibile nell'altro.

# GENERAZIONE DELLA COPPIA. La chiave PRIVATA non esce MAI dal computer.
ssh-keygen -t ed25519 -C "manuel@cyberonions.it"

# Genera due file:
#   ~/.ssh/id_ed25519       -> CHIAVE PRIVATA. Segreto assoluto.
#   ~/.ssh/id_ed25519.pub   -> CHIAVE PUBBLICA. Si dà a chiunque.

# L'unica cosa che dice il file pubblico:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... manuel@cyberonions.it

Ecco il punto, che è tutto l'affare:

  • la chiave pubblica si distribuisce apertamente, anche su un cartellino, anche in una mail;

  • la chiave privata resta sul computer, protetta da una passphrase;
  • ciò che è cifrato con la pubblica si decifra solo con la privata.

Tre usi, e sono tutti quelli che ti servono:

UsoCon qualeEffetto
Autenticazioneprivata firma, pubblica verifica"sono io"
Cifraturapubblica cifra, privata decifra"solo tu puoi leggere"
Firmaprivata firma, pubblica verifica"l'ho scritto io, è integro"

Da qui il nome: pubblico perché si pubblica, privato perché non si mostra. Non è una questione di grado di sicurezza fra le due, è una questione di direzione: una serve a mostrare, l'altra a custodire.

Perché non serve una password

Quando colleghi un repository a un server, invece didigitare la password ogni volta, la chiave pubblica finisce in ~/.ssh/authorized_keys sul server. Da quel momento la tua chiave privata dimostra chi sei.

Il vantaggio non è la comodità, è che una chiave non si indovina e non si trasmette. Una password attraversa la rete mille volte; una chiave privata non la lascia mai.

Il collegamento con Git, che è la parte operativa

Git non ti obbliga a usare SSH: funziona con HTTPS e token. Ma se usi SSH, il meccanismo è esattamente questo.

E qui c'è il punto che quasi nessuno spiega, e che genera il panico di tutti i principianti: i commit non viaggiano con la tua identità crittografata.

# Il nome e l'email nel commit sono DICHIARATIVI. Chiunque li puo' scrivere.
git config --global user.name "Manuel"
git config --global user.email "manuel@cyberonions.it"

# La chiave SSH firma il TRAFFICO con il server. Dimostra chi sei a LUI,
# ma non firma il contenuto del commit.
git commit -m "corretto il calcolo del totale"

Questa distinzione è la ragione per cui la cronologia Git non è firmata e va trattata come un documento non autenticato. Chiunque possa scrivere sul repository può scrivere un commit con un nome e una mail che non sono suoi.

La difesa è il commit signing: si firma il commit con la chiave privata, e la firma dice al lettore "questo contenuto è di chi dice di essere". È la cosa che distingue un repository in cui puoi fidarti da uno in cui devi fidarti della promessa di chi lo mantiene.

git config --global commit.gpgsign true
git config --global user.signingkey "YOUR_KEY_ID"

E se la cronologia è già compromised, non si risolve: riscrivere la storia è possibile (git filter-repo) ma cambia tutti gli hash e invalida ogni firma. Per questo la prevenzione vale più di qualunque riparazione.

La storia, che è più interessante di quanto sembri

1991-1998: il version control era unserver centrale

Prima di Git il modello era client-server. SVN, CVS e gli altri avevano un server che era la fonte della verità, e ogni sviluppatore aveva una copia locale che sincronizzava.

Il modello è semplice da spiegare e ha tre problemi che sono diventati insoportabili quando i team si sono allargati:

  • se il server è giù, non lavori;
  • ogni operazione è una comunicazione di rete, e la rete è lenta;
  • per ogni modifica servono permessi e lock, e i lock creano conflitti fra persone che lavorano su file diversi.

2002-2005: BitKeeper, e la rottura

Il kernel Linux era così grande che serviva qualcosa di diverso. Dal 2002 il suo sviluppo usa BitKeeper, proprietario, con licenza gratuita per il kernel.

Nel 2005 la licenza viene revocata. Il titolare del copyright, Larry McVoy, sosteneva che Andrew Tridgell avesse creato SourcePuller invertendo i protocolli di BitKeeper. Il fatto, comunque, è la revoca.

A quel punto Torvalds si trova con una scelta: il kernel Linux, e la sua capacità di coordinare centinaia di sviluppatori, dipende da uno strumento proprietario che può chiudere la porta in qualsiasi momento.

Lo stesso episodio fa nascere Mercurial, che oggi è minoritario ma è ancora usato, soprattutto da chi vuole la stessa idea di Git con un modello di licenza più semplice.

3 aprile 2005: Git nasce

Torvalds non voleva aspettare che qualcun altro risolvesse il problema, e non voleva discutere di licenze. Scrive il suo.

I suoi tre criteri di progetto sono la parte interessante, perché sono esattamente la risposta ai tre problemi del modello client-server:

  • prendere CVS come esempio di che cosa non fare: se in dubbio, decidi l'esatto opposto;

  • supportare un flusso distribuito, come BitKeeper;
  • safeguarde fortissime contro la corruzione, accidentale o malevola.

E il criterio che ha reso il progetto praticabile è una cifra: un applicazione di patch che impiegava 30 secondi per applicare una patch e aggiornare i metadati era troppo lenta. Il suo requisito era tre secondi. Perché nel kernel la sincronizzazione con altri maintainer poteva richiedere 250 operazioni di quel tipo in una volta sola.

Questi criteri esclusero tutti i sistemi di controllo versione in uso all'epoca. Non esisteva niente che li soddisfacesse: da qui la decisione di scriverne uno.

La cronologia è incredibilmente rapida:

  • 3 aprile 2005: inizio dello sviluppo;
  • 6 aprile: annuncio del progetto;
  • 7 aprile: Git è già self-hosting, il repository del progetto è versionato con Git stesso;

  • 18 aprile: primo merge di più branch;
  • 29 aprile: benchmark, 6,7 patch al secondo sull'albero del kernel;
  • 16 giugno: Git gestisce il rilascio del kernel 2.6.12.

Dall'inizio alla release del kernel in undici settimane. Il 26 luglio 2005 Torvalds passa la manutenzione a Junio Hamano, che cura la release 1.0 il 21 dicembre 2005.

Quel self-hosting del secondo giorno è il dettaglio che vale la pena notare: Git è nato con il proprio repository su Git. Una scelta che dice più di qualsiasi documento sul progetto.

Il nome

Torvalds ha detto chiaramente che non aveva cercato un nome neutro:

"Sono un bastardo egoista, e nomino tutti i miei progetti dopo me stesso. Prima 'Linux', ora 'git'."

In inglese git è un insulto, una persona sgradevole o stupida. La pagina di manuale lo descrive come "the stupid content tracker". Il file README ne dà cinque significati alternativi, e i due più citati sono l'acronimo Global Information Tracker e Goddamn Idiotic Truckload of Shit. Il sorgente lo chiama "the information manager from hell".

Il merito è di Torvalds stesso: ha chiamato una cosa che crea problemi con il nome del problema. È il tipo di umiltà che rende facile ricordare il nome.

1973-1977: RSA, e un segreto di venticinque anni

La storia delle chiavi pubbliche parte prima di Git, e ha un dettaglio che quasi nessuno conosce.

Nel 1973, nei laboratori di GCHQ — l'agenzia britannica di intelligence dei segnali — il matematico Clifford Cocks sviluppa un sistema a chiave pubblica equivalente a RSA. È segreto, e resta segreto per venticinque anni. Il documento viene declassificato nel 1997.

Nel 1976 Diffie e Hellman pubblicano l'idea della chiave pubblica, ma senza una funzione a senso unico che funzioni: la difficoltà di fattorizzare non era ancora studiata.

Nel 1977, al MIT, Ron Rivest, Adi Shamir e Leonard Adleman pubblicano quello che chiamano RSA, dalle iniziali dei loro cognomi. Lavorano per un anno a una funzione difficile da invertire: Rivest e Shamir, informatici, proponevano i candidati, e Adleman, matematico, ne trovava le debolezze. Provano anche altri approcci, incluso il knapsack crittografico.

Il fatto da sapere è che non è stato un caso isolato: RSA era stato inventato due volte, e una delle due è rimasta segreta. È il motivo per cui la sicurezza crittografica non può essere costruita sull'idea che l'ha pensata per prima l'ha pensata bene.

Oggi RSA si usa con chiavi da 2048 a 4096 bit, soprattutto per firma e per cifrare chiavi simmetriche, non dati. Per i dati si usa la crittografia simmetrica, che è più veloce. La sicurezza di RSA poggia sulla difficoltà di fattorizzare il prodotto di due numeri primi grandi; un attacco dimostrato ha riguardato una chiave di 829 bit nel 2010.

E c'è una nota che vale per chi valuta le minacce future: l'algoritmo di Shor, su un computer quantistico, romperebbe RSA in modo efficiente. Non è un problema di oggi, ma è il motivo per cui esiste il passaggio a crittografia post-quantistica.

Due date da Git che il mestiere conosce male

2017, l'attacco SHAttered. Due ricercatori dimostrano un attacco pratico a SHA-1, la funzione di hashing che Git usava internamente per identificare i commit. Git è stato modificato per usare una variante resistente. Per Torvalds la risposta è stata che SHA-1 serviva soprattutto a proteggere dalla corruzione accidentale e che la sicurezza vera sta nella firma, altrove.

2015, CVE-2015-7545. Una vulnerabilità che permetteva esecuzione di codice arbitrario, sfruttabile convincendo qualcuno a clonare un URL costruito male. È il motivo per cui non si clona mai un repository da sconosciuti su una macchina di lavoro.

La regola che usiamo noi

Il ragionamento di CYBER ONIONS su tutto questo è breve:

Il repository è la cosa che non vuoi perdere. Tutto il resto è ricostruibile.

Da qui tre pratiche che seguiamo ogni giorno:

  • il repository non è il backup. Se la macchina muore e non c'è una copia altrove, il lavoro è perso. Ciò che è su GitHub o GitLab è una copia; se il codice è segreto, è l'unica copia e va trattata come tale.

  • niente segreti nel repository, per nessun motivo. Un file .env committato per errore resta nella cronologia per sempre, anche se dopo lo rimuovi. Il .gitignore va messo prima del primo commit.

  • le chiavi private non viaggiano. La privata sta sulla macchina, la pubblica su tutto il resto. E la chiave di firma non è la chiave di accesso: tenere separate le due è una delle buone pratiche di base.

Il motivo di fondo è quello che abbiamo già scritto in Open source: perché conviene al software a pagamento: se puoi leggere il codice di una cosa di cui dipendi, quella cosa non è solo tua. Il repository aperto è il primo passo, e la cronologia firmata è quello che lo rende verificabile.

Se ti ricordi una cosa sola

Git non serve a salvare le versioni. Serve a sapere chi ha cambiato che cosa, quando e perché — e quando arriva il momento in cui una domanda ha due risposte possibili, quella è l'unica cosa che ti salva il lavoro.