git
In figura, possiamo osservare 4 livelli ordinati:
- working directory (WD): rappresenta la configurazione della directory di lavoro sul filesystem - esiste indipendentemente da git. Può essere vista come l’unione dei tracked and untracked files;
- index (o area di staging): insieme dei tracked files da git.
- (\(n\)?) local repository: insieme delle modifiche committate e relativo storico.
- (\(n\)) remote repository: branch remoto; è possibile avere sia più branch per progetto remoto che più progetti remoti configurati.
Il termine repository è abbastanza misleading, perché è comunemente associato ad un progetto mentre in questa astrazione a livelli corrisponde di fatto a un branch.
Il passaggio tra un livello e l’altro non è mai automatico, ma è sempre esplicitato da un’operazione.
Operazioni di base
È consigliata la lettura di git Cheatsheet.
Per ogni branch c’è un puntatore all’ultimo commit di tale branch. L’HEAD punta all’ultimo commit in cui siamo: normalmente corrisponde al puntatore del branch corrente; quando non è così siamo in una situazione di HEAD scollegato. È utile potersi spostare tra i commit per controllare revisioni precedenti, ma in caso di nuovi commit è importante creare un nuovo branch per poterci riferire ad esse.
git commit
— record changes to the repository
Il comando git commit ci permette di salvare del contenuto dall’index al branch locale.
Dopo aver creato il commit, l’HEAD
e il puntatore al branch corrente puntano al nuovo commit.
Anche il contenuto dell’index equivale al contenuto del commit.
--amend
Con l’opzione --amend è possibile rimpiazziare facilmente l’ultimo commit con uno nuovo.
git switch
— switch branches
Il comando git switch ha un sottoinsieme delle funzionalità del comando git checkout ed è più semplice da utilizzare.
Permette di passare a un nuovo branch semplicemente modificando l’HEAD (e di conseguenza il contenuto dell’index e dei file).
git merge
— join two or more development histories together
Il comando git merge è utile per unire branch (o più in generale alberi) insieme.
Se i due branch non sono divergenti, il merge avviene in modo banale con un fast-forward: nessun ulteriore commit verrà cambiato, verrà solo modificato il puntatore del branch e l’HEAD.
Per forzare la creazione di un merge di commit (in gitFlow è apprezzato) occorre utilizzare l’opzione --no-ff
.
In tutti gli altri casi, il merge può concludersi con successo oppure possono avvenire conflitti. Per risolverli, git ci proporrà un’interfaccia simile alla seguente.
<<<<<<< yours:sample.txt
Conflict resolution is hard;
let's go shopping.
=======
git makes conflict resolution easy.
>>>>>>> theirs:sample.txt
Una volta risolti tutti i conflitti è sufficiente commitare le modifiche concludendo quindi il merge.
La tecnica utilizzata per implementare la fusione di due rami è chiamata 3-way merge, inizialmente vengono considerati i commit HEAD dei due branch da unire e il primo commit comune a questi due (ovvero il commit da dove è iniziata la diramazione). A questo punto git cercherà di identificare le parti dei file modificate nelle diverse diramazioni sfruttando i commit considerati, se viene riscontrato un cambiamento della stessa porzione di file in entrambe le diramazioni significa che si è verificato un conflitto, e quindi verrà richiesto l’intervento manuale dell’utente, altrimenti verranno uniti automaticamente i due rami in un commit di merge.
git reset
— reset current HEAD to the specified state
Il comando git reset reimposta il contenuto dei file nell’index (e, opzionalmente con l’opzione --hard
nella WD) all’ultimo commit puntato da HEAD o ad un altro commit.