Breve introduzione a Git

Git è un sistema di controllo versione distribuito estremamente famoso e diffuso, al punto da essere entrato nel patrimonio di competenze di base che penso sia opportuno avere se si lavora con computer e dati, di qualsiasi tipo. Non a caso è anche incluso tra le competenze offerte nel progetto Library Carpentry, che si rivolge ai bibliotecari.

Ma cosa vuol dire controllo versione distribuito? È un software che consente di tenere traccia dei cambiamenti che avvengono sui file a cui lavoriamo (e quindi della loro versione). Pensato per il codice sorgente del software, può essere analogamente utilizzato per la gestione di dati e testi, se lavoriamo con file di testo semplice (Go plain text!). È distribuito perché non si basa su un unico server centralizzato: può essere usato in locale – sul nostro PC – quindi sincronizzato su un server esterno e da lì condiviso e sincronizzato con vari altri utenti. È anche software libero, per cui possiamo utilizzarlo liberamente e per ogni scopo.

Non sono affatto esperto di Git, tuttavia siccome lo sto usando per alcuni lavori (tra tutti il layout per OJS e il workflow per impaginare con markdown e pandoc) ne approfitterei per fare qualche appunto schematico.1

Concetti base e glossario

Siccome vogliamo tenere traccia delle revisioni di un nostro progetto, vorremo creare un archivio che lo contenga (codice, dati o testo che sia) insieme alle sue modifiche: il repository. Creeremo il repository all’interno della cartella in cui lavoriamo al nostro progetto (working directory), ma potremo successivamente sincronizzarne delle copie su altri computer e su server online (repository remoti, pubblici o privati, solitamente su servizi terzi quali GitHub, BitBucket o GitLab).2

Schema dell'area di lavoro in Git: working directory, staging area e repository

Le basi dell'area di lavoro in Git

Creato il repository aggiungeremo (add) i file su cui stiamo lavorando a un indice (index) che terrà traccia dei cambiamenti, quindi potremo lavorare al nostro progetto: saremo noi a decidere quando vorremo salvare uno stato della nostra working directory.

Man mano che interveniamo sui file potremo decidere di controllare le differenze (diff) intervenute; una volta terminate le modifiche decideremo di rimuoverle (reset), di metterle da parte (stash), o di marcare i file (add) in stage affinché le modifiche siano registrate nel prossimo commit. Il commit è l’azione di registrare all’interno del repository una istantanea (snapshot) di ciò che si trova in stage. Ogni commit avrà un identificativo univoco (l’hash) e un nostro messaggio opzionale. L’elenco (log) dei commit rappresenta lo storico di cui è costituito il repository, mentre l’ultimo snapshot è chiamato HEAD.

Repository, index, stage, commit… Dov’è tutta sta roba?

Nella working directory vedo solamente i miei file, l’intero repository con i vari commit, l’indice etc è contenuto nella sottocartella .git, che è nascosta e che viene usata ogni volta che lanciamo un comando di Git, come ad esempio git log per vedere il registro dei commit.

Più di un registro

Nei sistemi di controllo di versione non ci si limita a tener traccia delle modifiche, ma sono possibili operazioni più avanzate, quali:

Schema del flusso di lavoro in Git: repository con i branch, stash, repository remoto

Un po' più di dettaglio (clicca per ingrandire)

Comandi di base

Repository

Possiamo creare un repository nel nostro computer (in locale, quindi) per poi eventualmente fare il push in un repository su un server remoto:

git init # crea un repository locale

Oppure possiamo voler ottenere una copia di un repository remoto (nostro o altrui) sul nostro computer:

git clone linkalrepositoryremoto

Stage

git status # mostra i file (tracciati e non) nella cartella di lavoro, esclusi i file ignorati!
git diff # mostra le modifiche ai file
git add nomefile # inizia a tracciare le modifiche a quel file

Oppure su più file

git add '*.csv' # aggiunge tutti i file con estensione csv, anche se in sottocartelle

Commit

git status
git add nomefile # se ho modificato il file devo rimetterlo in stage
git commit -m "oggetto del commit"

oppure se vogliamo saltare lo staging:

git commit -am "oggetto del commit"

il parametro -a aggiunge automaticamente tutti i file di cui vengono tracciate le modifiche e che sono cambiati dall’ultimo commit, anche se non si trovano in stage.

Log

Il registro dei commit è un elenco cronologico dei commit con il loro hash, l’autore e l’eventuale messaggio.

git log # mostra il registro dei commit

Esempio di output:

commit a50de50268242decb41fcee4431449ccee6d3f59
Author: Tizio Caio <email-di@lavoro.it>
Date:   Mon Aug 6 13:53:51 2018 +0200

    terzo commit

commit 446212925336d62adb062ad32fd1d08a3e4ec25e
Author: Tizio Caio <email-di@lavoro.it>
Date:   Mon Aug 6 13:38:06 2018 +0200

    secondo commit

commit 1c6cf69e8284826034153fca4effe6fd5103d08d
Author: Tizio Caio <email-di@lavoro.it>
Date:   Mon Aug 6 13:07:25 2018 +0200

    il mio primo commit

una comoda visuale è quella a riga singola, con l’hash abbreviato, ottenibile con git log --oneline:

a50de50 terzo commit
4462129 secondo commit
1c6cf69 il mio primo commit

Stash

Se abbiamo dei lavori in sospeso non ancora completati, ed abbiamo bisogno di eliminarli provvisoriamente per avere la cartella di lavoro pulita, è probabile che non vorremo fare un commit. Ci viene in aiuto git stash, che prende ciò che si trova nella nostra working directory (che sia in stage o meno) e lo mette da parte, riportandoci all’ultimo commit (l’HEAD).

# pulisce la working directory salvando quanto presente
git stash

# pulisce la working directory assegnando un messaggio allo stash, per riconoscibilità
git stash save "mio messaggio"

# mostra l'elenco degli stash conservati
git stash list

Gli stash conservati sono numerati dal più recente, a partire da 0 (stash@{0}, stash@{1} etc.) e, se privi di messaggio, mostrano l’ultimo commit a cui erano stati applicati.

# recupera e mette nella working directory l'ultimo stash (il più recente, ossia stash@{0})
git stash pop

Annullare le modifiche

Abbiamo varie opzioni a disposizione – non tutte sono esenti da problemi – a seconda di cosa vogliamo fare:3

Impostazioni

Tramite git config possiamo impostare i nostri dati (nome ed email) a cui saranno associati i lavori (ma non solo…). La configurazione può essere impostata a livello locale (singolo repository), globale (utente) e di sistema (il computer). Git utilizza i parametri a livello locale, se disponibili, altrimenti cerca quelli globali etc.

# elenca la configurazione attuale
git config -l

# imposta a livello globale il tuo nome
git config --global user.name "Tizio Caio"

# imposta a livello locale (nel repository) un indirizzo email
git config --local user.email "email-di@lavoro.it"

Gitignore

Non tutto ciò che sta dentro la mia cartella di lavoro deve essere tracciato da Git. File nascosti e di backup, file di test, risultati di prove varie o altro: potrei ritrovarmi con vari file a cui non vorrò mai fare git add. È quindi possibile specificare tramite un file nascosto (.gitignore) una serie di regole per escludere quei file, specificando i pattern nei nomi dei file. Salvo casi particolari è utile inserire un file .gitignore nella cartella principale della nostra working directory.

I vari modi per indicare percorsi in .gitignore sono anche riassunti una comoda tabella.


  1. Naturalmente esiste una infinità di guide e tutorial sull’uso di Git; personalmente mi trovo molto bene con i tutorial di BitBucket: https://www.atlassian.com/git/tutorials.
  2. GitHub è la più grande comunità di codice open source; offre repository online gratuitamente a patto che siano pubblici (e privati a pagamento); BitBucket offre repository sia pubblici che privati, gratuitamente se per team di massimo 5 utenti. Entrambi offrono altri servizi avanzati, esistono comunque molti altri servizi indie.
  3. inizialmente era presente un quinto punto che citava l’uso di git checkout, ma è meglio trattarlo più estesamente in un post successivo. Inoltre il comando git rm era erroneamente citato senza l’opzione --cached.

comments powered by Disqus