Introduzione al versioning
Il software attraversa molteplici fasi di sviluppo e versioni, dal momento della modifica del file sorgente fino alla creazione di versioni di test, alpha, beta e finali. Queste versioni vengono create per diverse piattaforme e per diversi rilasci di prodotto.
Il versionamento del codice gestisce e tiene traccia di queste diverse versioni, consentendo il recupero di versioni precedenti per risolvere eventuali bug introdotti nelle versioni più recenti e la gestione di più versioni in contemporanea.
Questi strumenti agevolano lo sviluppo collaborativo e la gestione di documenti e programmi, estendendosi anche a file binari come le immagini. Il versionamento del codice è una pratica comune e utile non solo per il codice sorgente, ma per l’intera base di codice, inclusa la documentazione e i file di configurazione.
Tipi di sistemi di versionamento
Esistono diversi sistemi per il controllo di versione(version controlsystems-VCS):
-
Locali: mantengono un archivio dei cambiamenti del software sul computer usato per lo sviluppo. Hanno il vantaggio di essere molto facili da usare perché non è richiesta nessuna attività al programmatore, ma lo svantaggio di non consentire la collaborazione con altri utenti, la mancanza di sicurezza dato che non offrono una funzione di backup e il fatto che la storia della codebase è vista file per file, senza la possibilità di sapere quali file fossero in quale versione in un certo momento dello sviluppo.
-
Centralizzati: sono gli strumenti più “tradizionali”, come CVS o Subversion. L’archivio è mantenuto su di un server centrale, mentre gli sviluppatori lavorano su una copia locale di uno degli stati del software. Si usano delle operazioni di checkout per prelevare uno stato del sistema dal server(es.la versione più recente), e con un’operazione di commit si inviano le proprie modifiche per aggiornare lo stato sul server.
-
Distribuiti: sono i sistemi, come Git o Mercurial, in cui il sistema locale ha una copia completa della storia dello sviluppo, per cui si può lavorare con sistema diversionamento anche senza connessione. Dato che sono distribuiti non si ha più un server centrale di riferimento se non per convenzione comune.
Hello git: workflow di base
Git è un software che permette di tenere traccia dei cambiamenti fatti su un progetto nel tempo. Git ricorda ogni modifica, tenendone traccia e dando la possibilità di accedere ad ogni versione salvata del progetto.
I 3 stadi di un progetto git
Possiamo semplificare (di molto) il workflow di git dividendolo in 3 parti:
- Effettuo delle modifiche al progetto (aggiunta/rimozione/modifica di files).
- Aggiungo le modifiche alla lista di modifiche pronte per essere “committate” (detta staging area).
- Salvo i cambiamenti in una commit, le commit vengono conservate nella git repository.
La Working Directory è quindi la directory del progetto nello stato attuale
Convenzioni riguardanti i commenti:
- Dovrebbero essere in Present Tense
- Non dovrebbero superare i 50 caratteri
I files in verde sono gli staged files, quelli rossi sono quelli in attesa di essere aggiunti alla staging area
Al posto dei nomi dei files volendo si possono usare le wildcards offerte da bash!
git diff: vedere le modifiche effettute
Git ci permette di vedere le differenze tra i files della working directory e la staging area (molti editor/IDE supportano Git e forniscono uno strumento grafico per vedere questo, naturalmente essi si appoggiano al comando fornito da git).
git log & git blame: lo storico
Le commit possono essere viste grazie ad uno storico (come vedremo, lo storico può essere sia locale che remoto).
È inoltre possibile per ogni riga di ogni file sapere chi (ed in quale commit) ha effettuato l’ultimo cambiamento a quella riga.
Screenshot di una sezione dello storico in modalità grafo:
In arancione possiamo vedere un codice alfanumerico di 40 caratteri, questo è l’hash o SHA della commit e viene usato come identificativo per riferirsi alla commit.
Backtracking: ritornare sui propri passi
git show e head commit
HEAD
identifica la commit in cui si è attualmente (spesso coincide con l’ultima commit dello storico, ma non è detto)
In un certo senso
git show
è come ungit log
SOLO di una commit +git diff
git checkout
git reset
Qui (come in tutti i comandi visti fin ora per riferirsi ad una commit bastano i primi 7 caratteri dell’hash)
Branching
Fin ora abbiamo sempre lavorato nel branch creato automaticamente con la init
di un progetto git, ovvero master
(recentemente si vede main
al posto di master).
Git ci permette di creare infiniti branch, in questo modo è possibile avere infinite versioni del progetto che coesistono allo stesso momento, le modifiche apportate dai vari branch possono essere allineate tramite una merge.
Spesso i branch sono utilizzati per aggiungere nuove feature e per far lavorare in parallelo più sviluppatori.
Parentesi riguardo git log
Come si vede nell’immagine qui sotto git log
di default mostra solo lo storico delle commit relative al branch attivo, è però possibile stampare a video lo storico di tutte le commit utilizzando il flag --all
.
git merge
Quando possibile appoggiarsi sempre ad una soluzione grafica per i merge, in modo da gestire con più facilità i possibili conflitti.
Se il branch corrente è semplicemente più indietro di qualche commit il risultato della merge sarà un fast forward
git rebase
git rebase
è un’operazione avanzata di gestione dei rami che consente di modificare la storia dei commit in un repository. Più specificamente, il comando git rebase
consente di riapplicare una serie di commit su una base differente rispetto a quella originale in cui sono stati creati.
Di solito, questo viene fatto per due ragioni principali:
-
Integrare modifiche da un ramo all’altro: Se hai creato un ramo separato per lavorare su una funzionalità e nel frattempo ci sono state modifiche sul ramo principale, puoi utilizzare
git rebase
per integrare le modifiche dal ramo principale nel tuo ramo di funzionalità senza creare commit di merge aggiuntivi. -
Riorganizzare la storia dei commit: Può capitare che i commit siano stati creati in un ordine non ottimale o che vogliamo riorganizzare la storia dei commit per renderla più comprensibile o pulita. In questo caso,
git rebase
può essere utilizzato per riorganizzare, combinare, modificare o eliminare i commit.
Teamwork: come collaborare
Per collaborare serve che ogni sviluppatore abbia:
- Una replica del codice sul suo computer
- Un modo per tenere traccia delle modifiche sul suo computer
- Accesso alla versione definitiva del progetto
Tutto questo può essere ottenuto utilizzando i remotes
.
Un remote è una shared git repository, ovvero messa su di un server git.
git clone
git remote
Il nome di default, ed usato per convenzione, della cartella remota principale è origin.
Se si vuole il nome può essere anche cambiato.
Come si vede sopra origin è specificato 2 volte, una per le fetch ed una per le push. Vedremo più avanti il significato preciso di queste azioni, il concetto base da sapere è che fetch indica la lettura e push la scrittura
git fetch & git pull
Se mentre stiamo lavorando un altro sviluppatore pusha delle commit sulla repository remota ci serve fare una git fetch
per avere accesso a quei cambiamenti.
La fetch non aggiorna il branch, ma semplicemente controlla lo stato del branch remoto corrispondente al nostro branch.
Per recuperare le modifiche remote si possono usare 2 metodi equivalenti:
git push
La push serve per mandare le commit locali sul branch corrispondente della repository remota
BONUS: Creare un proprio git server
Questa guida elenca i passaggi da fare su un sistema debian-based (nello specifico è presa da un sito che usa un rasperry pi, con raspbian)
Link tra le fonti.
Installazione e configurazione di git
Per motivi di sicurezza e semplicità, è bene che i repository Git appartengano ad un apposito utente, che chiamiamo git. Tale utente avrà come home personale, che è poi la directory dove andranno i repository, /mnt/disco/git
(assumendo che /mnt/disco sia la directory sulla quale è montato il disco esterno).
Creiamo l’utente (e il relativo gruppo):
Creare una repository
Siamo dunque pronti a creare il nostro primissimo repository. Esistono due tipi di repository Git: quelli semplici, che contengono i file della versione attuale e una directory .git con le informazioni necessarie al versionamento, e i repository bare, che espongono tutta la struttura del versionamento e non mostrano comodamente la versione corrente. Il primo tipo viene utilizzato per i repository locali, mentre il secondo è per i server, come in questo caso.
Il nostro primo repository sarà chiamato test. Per crearlo, dobbiamo prima di tutto creare una directory test.git nella home dell’utente git, per poi inizializzarci dentro un repository bare. Passiamo dunque all’utente git e creiamo il repository:
Ora è possibile clonare la repo in locale ed utilizzare il server git come remote
!
Si assume che raspberrypi.local sia l’indirizzo mDNS del nostro dispsitivo:
Comandi utili ad interfacciarsi via SSH
Spunti per esperimenti futuri:
- Dockerizzare il servizio che si occupa di gestire le directory remote
- Creare una pipeline CI/CD
Esistono modi migliori per farsi git server più articolati come ad esempio tirare su in locale un gitlab o gitea o gogs.