Repository, commit e branch: il vocabolario di base

Git è un sistema di controllo di versione distribuito: ogni persona che lavora a un progetto ha sul proprio computer una copia completa dei file e di tutta la loro cronologia. GitHub non sostituisce Git, lo ospita e ci costruisce sopra collaborazione, revisione del codice e automazione. Prima di poter ragionare su pull request, permessi o workflow, servono tre concetti che ritornano in ogni altro dominio dell’esame: repository, commit e branch.

Il repository: i file più la loro cronologia

Un repository è l’elemento più basilare di GitHub. Il modo più semplice di immaginarlo è come la cartella di un progetto: contiene tutti i file del progetto, documentazione compresa, e conserva la cronologia delle revisioni di ciascun file. È questa seconda metà della definizione a distinguerlo da una normale cartella condivisa: un repository non tiene solo lo stato attuale dei file, ma anche tutte le versioni precedenti, con l’indicazione di chi ha cambiato cosa e quando.

Alla creazione si può inizializzare un repository con alcuni file di servizio: un README, cioè il documento che descrive il progetto, un file .gitignore con le regole sui file da ignorare, e una licenza software. Ogni repository ha inoltre una visibility: public, accessibile a chiunque su internet; private, accessibile solo a chi riceve esplicitamente l’accesso; internal, disponibile per le organizzazioni che fanno parte di un enterprise account su GitHub Enterprise Cloud.

L’esame verifica che tu sappia riconoscere il repository come unità che contiene file e cronologia, e che sappia distinguerlo dai livelli superiori: un’organizzazione contiene repository, un repository non contiene organizzazioni.

Il commit: un’istantanea con un messaggio e un autore

Un commit è una singola modifica a un file o a un insieme di file. La cronologia di un progetto si legge come una sequenza di istantanee nel tempo, e ogni istantanea è un commit. Quando lo crei, Git genera un identificatore univoco, chiamato SHA o hash, che tiene traccia delle modifiche specifiche registrate, di chi le ha fatte e di quando.

A ogni commit è associato un commit message, cioè una descrizione che spiega perché è stata fatta quella modifica. La documentazione suggerisce che idealmente ogni commit contenga una modifica isolata e completa: così diventa facile annullarlo se in seguito si sceglie un approccio diverso. Il termine HEAD indica il commit di riferimento di un branch, di solito il più recente in cima alla linea.

La confusione tipica da evitare è credere che salvare un file equivalga a fare un commit. Sono due passaggi distinti, e c’è un terzo passaggio: finché non lo invii al server, un commit esiste soltanto nella tua copia locale.

Il branch e il branch predefinito

Un branch è una versione parallela del repository. È contenuto dentro il repository stesso e non tocca il branch primario, così puoi lavorare liberamente senza intaccare la versione considerata definitiva. Quando crei un branch a partire da un altro, parti da una copia dello stato di quel branch in quel preciso momento.

Ogni repository ha almeno un branch, creato da Git al momento dell’inizializzazione, e su GitHub si chiama main. È il default branch: la base per i nuovi commit e per le nuove pull request. Le modifiche fatte su un altro branch non finiscono sul default branch finché non viene eseguito il merge, ed è esattamente questo il ciclo del GitHub flow: creare un branch, fare commit, aprire una pull request, ricevere la review, fare merge e infine cancellare il branch. Nella vista Branches del repository trovi il default branch elencato a parte, e filtri come Active e Stale per riconoscere i branch su cui si lavora e quelli abbandonati.

Attenzione a non confondere branch e fork: il branch vive dentro lo stesso repository, il fork è una copia del repository sotto un altro account.

Locale e remoto: clone, fetch, pull, push

Il remote è la versione del repository ospitata su un server, tipicamente GitHub.com, e il remote predefinito si chiama per convenzione origin. La connessione avviene tramite un URL, che può essere in formato HTTPS o SSH.

Quattro comandi legano la copia locale al remoto. Clone crea in locale la copia di un progetto che esiste già in remoto, comprensiva di tutti i file, la cronologia e i branch. Push invia al repository remoto i commit fatti localmente. Fetch porta in locale le modifiche presenti sul remoto senza integrarle, così puoi esaminarle prima. Pull invece scarica le modifiche e le unisce alla tua copia in un solo passaggio.

Proprio qui si concentra la confusione più frequente in sede d’esame: fetch osserva, pull osserva e unisce. Ricorda inoltre che scaricare un archivio ZIP del codice non è un clone, perché non porta con sé né la cronologia né il collegamento al remoto.