Git: guida passo-passo per niubbi volenterosi

Ciao a tutti amici della rete! 👋

In questa guida raccoglierò tutte le principali cose che chi vuole iniziare con Git è giusto sappia.

In altre parole proverò a scrivere un breve manuale passo-passo, nella forma che mi sarebbe piaciuto leggere quando ho incontrato per la prima volta lo strumento. 📗

Spero possa esserti di aiuto.
Se così fosse, o se hai correzioni e annotazioni da pormi, batti un colpo: i feedback fanno sempre piacere.

Pronto? Iniziamo.
logo di Git

Attenzione
Al momento questa guida è relativa la sola gestione di Git in locale.
Nei prossimi aggiornamenti del post verranno integrati gli aspetti relativi i repository remoti e l’utilizzo di Github e Gitlab.

Cosa è Git

Git è un software di controllo di versione:

si tratta di una applicazione che permette di tenere traccia di tutte le modifiche apportate al codice sorgente di un determinato programma (che si intende monitorare durante le varie fasi di sviluppo).

Git è un programma che permette una collaborazione decentralizzata.

Non è necessario un server centrale e gli sviluppatori possono collaborare tra loro in maniera parallela, senza essere per forza connessi in ogni istante.

Git non è il solo sistema di controllo di versione esistente, ma di certo è lo standard oggi universalmente riconosciuto in campo informatico.

Il creatore di Git è nientepopodimeno Linus Torval, il papà di Linux. 🐧
Torvadl ha iniziato a sviluppare Git proprio come strumento di controllo per le sue personali attività di development sul kernel del sistema operativo.

Come funziona Git?

Vediamo subito i concetti base che stanno dietro Git.

Si tratta di una prima parte un po’ teorica che potrebbe sembrarti astratta all’inizio.

Tranquillo, diventerà sicuramente più chiara quando prenderemo in mano lo strumento con degli esempi pratici di utilizzo.

Lo sviluppo del software in Git viene idealizzato con il concetto di rami (branch).

Esiste un ramo principale di partenza, detto master.

Lo sviluppo evolve con la modifica, cancellazione o inserimento, di righe a partire da uno stato iniziale.

Ogni registrazione di un nuovo stato è detta commit.

Il commit è un momento importante dello sviluppo in cui si decide di “congelare” lo stato dei lavori, commentando e lasciando traccia del lavoro svolto. 🏁

Gli sviluppatori possono lavorare contemporaneamente anche su rami paralleli (branch) che partono da un commit del ramo master.

Successivamente le modifiche di un branch possono essere inglobate nuovamente sul ramo principale tramite una operazione di merge.

È Git che si farà carico del compito di individuazione delle differenze tra i vari commit e branch, prima di nuove fasi di commit.

Evidenzierà all’utente ciò che è variato, tenendo traccia di tutte le modifiche.

Permetterà inoltre di poter tornare in qualsiasi momento allo stato di una determinata fase di commmit.

Un flusso di controllo versione Git

Un flusso di versioning con Git: c’è il ramo principale (master, quello in arancio) e alcune branch di sviluppo parallelo (che in alcuni casi ritornano sul ramo primario). I commit sono rappresentati dai punti.

Git può funzionare sia in locale che in sincronizzazione con un server remoto.
È per questo che si tratta di un sistema di controllo distribuito e, ripeto, decentralizzato.

Git lavora su directory:

Scegli di monitorare una cartella, lanci Git su di essa e da allora verranno tracciate tutte le modifiche che effettuerai nell’ambito di quello specifico contesto.

Lo stato dei file in Git

Immagina Git come un guardiano che “veglia” sui file di una certa cartella-progetto.

Tu dirai a Git che file guardare e lui sarà lì e osservarne le evoluzioni, i cambiamenti. 👀

I file nella cartella monitorata da Git possono avere vari stati:

  1. Non tracciato, Untracked: il file non è stato preso in considerazione da Git
  2. Modificato, modified: rispetto l’ultimo salvataggio/commit il file è cambiato
  3. Staged: il file è marcato per essere salvato sul prossimo commit. Solo i file in staging area verranno salvati sul commit!
  4. Committed: il file, e una sua copia, sono stati congelati in quel preciso istante sul database di Git.

Più avanti troverai una bella immagine che riepiloga il ciclo di vita di un file in Git.
I relativi stati ti saranno subito più chiari.

Inizializzare Git

Andiamo al sodo, finalmente.

Come fare per inizializzare Git e cominciare a tenere traccia di un progetto sotto una determinata cartella?

Basta aprire il terminale, recarsi nella cartella da monitorare e digitare:

git init

Pochi istanti è Git sarà avviato.

Ci accorgiamo subito che su una cartella abbiamo lanciato Git perché viene creata una directory nascosta denominata .git.

È lì dentro che Git scriverà tutti i dati necessari all’esecuzione dei suoi compiti.

È caldamente sconsigliato andare a effettuare modifiche sul contenuto di questa cartella.
Se vuoi, curiosa pure, ma non modificare nulla: ne va di mezzo l’integrità del tuo progetto. 😉

Il comando status

Un comando che incontreremo spesso è status.

git status

Questo codice ti permette di visionare lo stato del progetto Git.

Subito dopo l’apertura del progetto, come è ovvio che sia, riceverai in outoput il seguente messaggio:


Sul branch master
Commit iniziale
nothing to commit (create/copy files and use "git add" to track)

Git ci sta dicendo che

  • c’è giusto un commit di partenza
  • siamo sul ramo, branch, master
  • se vogliamo iniziare a tracciare le modifiche dobbiamo creare qualche file e aggiungerlo alla staging area tramite il comando add

OK, prima di procedere con l’ultimo punto proviamo a creare un file.

Nell’esempio poco più sotto ho scritto un banale Hello World in Python.

Rilanciamo git status.
Cosa ne pensa Git del tuo nuovo file nel progetto?


Untracked files:
(use "git add ..." to include in what will be committed)

hello-world.py

nothing added to commit but untracked files present (use "git add" to track)

Ottimo. Git ti sta segnalando che c’è niente da committare.
Però si è accorto che c’è un nuovo file nella cartella: hello-world.py.
Per ora non ci andrà a sbirciare dentro, perché per lui è untracked.

Occorre chiedergli di seguirlo.

Iniziamo a tracciarlo, quindi! Pronto? 🙂

Iniziamo a monitorare: aggiungiamo file alla staging area

L’aggiunta di un file nella staging area può essere effettuata invocando il seguente comando:

git add nomefile

Quando dai ENTER il tuo file hello-world.py cambierà stato, passando da non tracciato all’area di staged.

Git, creo un file e le aggiungo alla staging area

Il primo commit

  1. hai lanciato il monitoraggio del tuo progetto
  2. hai creato il tuo primo pezzo di software
  3. ora cosa fai?

Il passo numero 3 potrebbe essere fissare lo stato dell’opera in un commit.

Un commit è un punto del progetto che si intende conservare perché particolarmente significativo.
Forse ora, con ciò che abbiamo in mano, è un’operazione che ha poco senso… ma proviamola ugualmente.

Puoi lanciare un commit con il comando:

git commit

Ti si aprirà l’editor di testo di sistema con una riga vuota iniziale.
Sotto ci sono varie righe di commento che riepilogano cosa è successo al tuo progetto dal precedente stato di creazione/commit.

Compila la prima riga con un commento descrittivo.
Cerca di essere significativo: in cosa consiste questa nuova versione del tuo software? ✍️
Quali sono le modifiche? Cosa rende lo sviluppo importante al punto da doverlo fissare in questo specifico momento?
Scrivi e salva.

Complimenti.
Hai appena effettuato il tuo primo commit su Git. 👍

primo commit su git

Visualizzare i vari commit: git log

Guarda la GIF animata sopra.
Dopo aver fatto il commit del nuovo file ho lanciato uno status e Git mi ha avvisato che era tutto commitato.
Ho quindi lanciato un nuovo comando:

git log

Ecco che il controllo inizia a prendere forma.
Ogni volta che chiederai un log a Git otterrai un elenco cronologico di tutti i commit registrati.

commit 3f1c275dcade9551e4c7060696132307d4bf2656 (HEAD -> master)
Author: Eugenio Nappi <eugenio@enappi.com>
Date: Tue Feb 12 10:40:12 2019 +0100

Prima versione del Ciao mondo

Ogni commit è identificato da un hash di 40 caratteri.

Affianco al commit è specificato dove è impostato il puntatore HEAD (ci servirà più avanti, quando parleremo di branch): in questo caso siamo sul ramo master).
Seguono infine riferimenti dell’autore del commit e la descrizione finale.

Ancora commmit: registriamo nuove modifiche

Ma modifichiamo ancora il file e vediamo come si comporta Git nel rilevare le sue variazioni.

Andando per logica, seguendo quanto fin ora appreso il processo dovrebbe essere il seguente:

  1. integriamo il nostro progetto
  2. quando le integrazioni ci interessano aggiungiamo il file modificato alla staging area, l’area di sosta dei file
  3. quando vogliamo congelare lo sviluppo della staging area in un punto preciso facciamo un commit

Il punto 2 è gestibile manualmente, dando il comando git add hello-world.py.

Diversamente puoi utilizzare il comando interattivo git add -p:
Git ti proporrà in automatico tutti i file del progetto che sono stati coinvolti nei precedenti commit e sono nello stato modified.

Dovrai confermare le modifiche (con il tasto y, yes) oppure gestire le singole eccezioni (sono abbastanza intuitive, se hai dubbi leggi la specifica sezione del manuale per capire quali sono e come agiscono).

Partendo dall’ultimo esempio ho aggiunta una nuova riga allo script in Python:

nuova riga, nuovo commit

Guarda come la conferma del nuovo commit viene proposta quando hello-world passa in stage.

  • Un nuova riga viene segnalata con il simbolo + in colore verde
  • Una riga mancante col simbolo – in colore rosso
  • Righe modificate vengono considerate come un aggiunta

Ora dovresti avere maggiore dimestichezza con il ciclo di vita dei file in Git.

Ti consiglio comunque di dare uno sguardo a questa immagine davvero ben fatta, presa dal manuale ufficiale:

ciclo di vita dei file in Git

Cambiamo ramo: git branch

Immagina di aver avuto un’idea geniale per lo sviluppo del tuo software. 💡

Vuoi implementarla, ma ancora non sai se può valerne la pena.
Hai bisogno di gestire le fasi di sviluppo in modo separato.

Decidi quindi di splittare il progetto su due binari: quello classico, master, continuerà sulle sue logiche.

L’idea innovativa, invece, partirà da un certo punto del master, e sarà dirottata su un nuovo ramo (per Git, ripetiamo, si dice branch).

Poi, magari in futuro, vedrai se è il caso o meno di travasare le nuove feature dell’idea (e il relativo codice) sul ramo master.

Se così fosse fonderai il branch idea con il branch master, con l’operazione di merge.

Ecco, detto in parole povere questa è la logica che sta dietro i rami di Git.

Ti faccio vedere un esempio partendo dal file di Hello World che avevamo lasciato in sospeso:

creazione di un nuovo branch su Git

Ecco cosa ho fatto:

  • volendo procedere con uno sviluppo innovativo ho deciso di creare un nuovo ramo che ho chiamato idea.
    Per farlo basta dare il comando
    git branch nomedelramo (nel caso specifico git branch idea)
  •  ho poi detto a Git di passare su quel ramo specifico, facendo puntare il puntatore HEAD al nuovo branch:
    git checkout nomedelramo (nel caso specifico git checkout idea)
    Attenzione: se non esegui questi operazione Git continuerà a committare sul branch master!
    Lanciato il comando Git avvisa del passaggio sul nuovo ramo.

creazione di un nuovo branch su Git

  • sono quindi partito con lo sviluppo della nuova idea:
    integrare al “Ciao mondo” un esoterico estrattore di numeri fortunati 😉
  • terminato lo sviluppo il file è stato messo il tutto in staged per poi committare.
    Occhio, stavolta il commit è stato lanciato con un comando più veloce:
    git checkout commit -m "messaggio"
  • se chiedo a Git un log ho subito ben chiaro cosa sta accadendo:

    > git log
    commit 928c9c36f0586fc01671ff53a3599ef549e8e0e3 (HEAD -> idea)
    Author: Eugenio Nappi <eugenio@enappi.com>
    Date: Tue Feb 12 14:13:10 2019 +0100
    prima idea: aggiunto numero della veritàcommit 86eeceadcca976b2ec77bfeca65bf7b4fc374477 (master)
    Author: Eugenio Nappi <eugenio@enappi.com>
    Date: Tue Feb 12 13:22:17 2019 +0100
    Aggiunto "Hello world"commit 3f1c275dcade9551e4c7060696132307d4bf2656
    Author: Eugenio Nappi <eugenio@enappi.com>
    Date: Tue Feb 12 10:40:12 2019 +0100
    Prima versione del Ciao mondo

L’ultimo commit è sul nuovo branch idea!
A seguire la storia del software sul ramo di partenza master.

Il bello però deve ancora venire.

Mi hai seguito testando passaggi simili sulla finestra del tuo terminale?
Prova a ritornare con un checkout sul branch master…

git checkout master

Il codice è proprio quello che avevamo lasciato all’ultimo punto di commit del branch master! 👌

Se non hai il tuo terminale sotto mano guarda qui, capirai subito:

passaggio da un branch all'altro

Se hai compresso appieno questo passaggio avrai anche capito definitivamente la potenza che un sistema di controllo di versione offre.

Stop a copia-e-incolla, stop a ZIP di cartelle dei tuoi progetti, stop ad appunti presi qui e là.

Tutto quello che ti serve è gestito in automatico da Git, che archivierà con cura ad ogni commit lo stato del tuo progetto. 😉

Un ultimo suggerimento per velocizzare la creazione di un nuovo branch:
se vuoi creare un ramo, e contestualmente effettuare l’operazione di checkout su di esso, utilizza il comando:
git checkout -b nomedelbranch

Unire due rami: git merge

Supponiamo che la fantastica idea di implementazione del tuo software sia valida.

La nuova feature è piaciuta in giro ed è da ritenersi ora matura.
È quindi giusto che lo sviluppo non sia più considerato solo una fase parallela di testing (il branch idea), ma venga assorbito sul progetto principale, ovvero il ramo master.

Cosa fare?
Quella da effettuare è una operazione di merge, unione di due rami.

Merge di due branch. Il ramo delle feature tip viene inglobato nuovamente sul ramo master. L’operazione crea un nuovo punto di commit.
fonte immagine: https://cs.atlassian.com/git/tutorials/using-branches/git-merge

Anche in questo caso Git saprà darti tutto il supporto di cui hai bisogno.
Attenzione, però.
In questa fase ci vorrà però un po’ più di attenzione da parte tua.

Quando chiederai a Git di unire due rami il software si comporterà nella maniera più intelligente possibile, ma la scelta di cosa scartare e cosa tenere (nel confronto tra le righe delle due versioni) spetterà a te.

Per fare merge del branch idea sul branch master dobbiamo in ordine:

  1. Spostarci sul ramo finale sul quale finirà il progetto, ovvero master:
    git checkout master
  2. Chiedere a Git di effettuare l’unione con il branch idea:
    git merge idea
  3. Gestire eventuali conflitti e chiudere il merge con un nuovo commit

Relativamente il punto 1: teoricamente potremmo voler chiudere il branch master facendolo convogliare su quello idea. È infatti solo regola comune, ma non obbligatoria, che master sia il branch principale su quale sviluppare il progetto operativo nel tempo.

Relativamente il punto 3: la gestione dei conflitti è l’aspetto per il quale ti dicevo è necessaria la tua attenzione.

Git rileva un conflitto se i due rami che stai cercando di unire hanno cambiato la stessa parte dello stesso file.

Git non sarà in grado di capire quale versione utilizzare. E lo chiederà a te.

Quando si verifica una situazione del genere, il programma di controllo di versione si interromperà prima del commit di unione chiedendoti di risolvere i conflitti manualmente.

Git: segnalazione di conflitti in fase di merge

Git utilizzerà degli indicatori visivi per segnalare la presenza di conflitti.

Tali indicatori sono:
<<<<<<<, =======, >>>>>>>.

La logica degli indicatori è la seguente:
<<<<<<< master
per porzioni di codice proveniente dal ramo master;

=======
separatore del contenuto tra i due rami;

>>>>>>> idea
per porzioni di testo in conflitto dal ramo idea, quello delle nuove funzionalità.

Generalmente il contenuto prima dell'indicatore ======= è il ramo ricevente e la parte dopo è il ramo che si unisce.

Identificato il conflitto bisogna entrare sul file e correggerlo.
Una volta pronti bisogna quindi lanciare un git add sui file che apparivano in conflitto (per dire a Git che sono stati risolti).
Quindi, si esegue un normale git commit per generare il commit di unione.

La parte della guida ufficiale che spiega come effettuare il merging e gestire i conflitti la trovi qui.

OK, direi che è ora di chiudere questa guida facendo chiarezza su un punto che avevamo lasciato in sospeso (il puntatore HEAD) e su come possiamo dire a Git di non tracciare un determinato file.

Il puntatore HEAD

Cosa è questo benedetto puntatore HEAD, già più volte citato?

L'ho chiesto a Google, che mi ha risposto così:
cosa è il puntatore head in Git

HEAD è un riferimento all'ultimo commit nel ramo di checkout corrente.
Puoi pensare a HEAD come al "ramo attuale".
Quando cambi rami con git checkout, la revisione HEAD cambia per puntare al punto del nuovo ramo.

In altre parole è lo speciale puntatore che permette a Git di capire in quale ramo è stato fatto l'ultimo checkout.

Per approfondire leggi questa parte della guida ufficiale (in italiano!) che spiega benissimo diramazioni (parlando anche del puntatore in questione).

Ignorare file

In un progetto è normalissimo non voler monitorare e versionare tutto il codice (come ad esempio dei file di log).

A tale scopo crea un file chiamato .gitignore, nella cartella principale del progetto.

Al suo interno puoi andarci a indicare i criteri da seguire per cartelle e file da ignorare.

Aggiungendo a .gitignore la riga:

*.log

stai, ad esempio, dicendo a Git di non monitorare i file con estensione .log, sulla cartella principale e su tutte le sottocartelle del tuo progetto.

Nonostante la sua funzione sia quella di ignorare, è buona norma aggiungere .gitignore ai file monitorati sul tuo progetto.
Se non lo hai fatto ancora: git add .gitignore.

Gitignore ha una marea di regole che permettono di personalizzare il monitoraggio.

Se hai bisogno di approfondire questo aspetto di consiglio di dare uno sguardo qui:
.gitignore file - ignoring files in Git | Atlassian Git Tutorial

Configurare nome, e-mail ed editor

Il comando config ti permetterà di configurare ogni aspetto di Git.

Le tre principali cose che però credo ti serva settare prima di partire seriamente sono:

Settaggio del tuo nome:
git config --global user.name "Scrivi il tuo nome"

Settaggio della tua e-mail:
git config --global user.email "Scrivi il tuo indirizzo di posta elettronica"

Settaggio dell'editor predefinito:
git config --global core.editor "tuo-editor"

Visualizzare tutto il flusso dei commit

Come già detto log è il comando da utilizzare per visualizzare cosa è successo nella storia del nostro (o altrui) sviluppo.

git log --graph --all --oneline

È il comando che ti consiglio per visualizzare in modo sintetico ma completo l’evoluzione di tutti i rami del tuo progetto.

Se vuoi affidarti a un tool grafico:

gitk --all
(ma prima installa gitk, su Ubuntu apt get install gitk 😉 )

Altre risorse su Git

Bene, siamo arrivati al termine di questa guida.

Ti lascio indicandoti un paio di risorse per consolidare i temi esposti e approfondire nuove funzionalità di questo straordinario strumento:

1. https://git-scm.com/book/it/v2
Il libro ufficiale di Git. 📖
Imprescindibile, totalmente gratuito e disponibile in tutti i formati (.mobi per Kindle, PDF, epub).
I primi capitoli sono tradotti anche in italiano.

2. https://www.html.it/guide/git-la-guida/
Il tutorial di HTML.it ✔

3. https://slides.poul.org/2017/corso-git/
Le slides del Politecnico Open Unix Labs. 🚀

4. https://www.youtube.com/watch?v=Y9XZQO1n_7c
Imparare Git in 20 minuti. 🙂

5. https://rogerdudler.github.io/git-guide/index.it.html
La “guida tascabile” per Git. 🙂

6. https://get-git.readthedocs.io/it/latest/
Una guida in italiano, realizzata con cura e amore da Arialdo Martini. ❤

Ultimo aggiornamento al post: 13-03-2019

Summary
Guida a Git: una veloce e completa introduzione per imparare le basi
Article Name
Guida a Git: una veloce e completa introduzione per imparare le basi
Description
Una guida a Git, il software di controllo di versione distribuito più amato: cosa è, come funziona, commit, branch e tutto ciò che devi sapere per iniziare.
Author
Posted in Linux, Python.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *