In questa lezione illustreremo alcune delle operazioni più comuni che è spesso necessario effettuare durante un progetto come cancellare, spostare, rinominare o ripristinare una versione precedente di un file. Vedremo inoltre come modificare l’ultimo commit presente nel repository.
Cancellare un file in git
Ovviamente se un file è nello stato ‘Untracked’, possiamo semplicemente cancellare il file visto che non è ancora presente nella Staging Area o nel repository.
[ cancellare_dei_file_in_git ] (master) $ touch mete_turistiche_dicembre.txt
[ cancellare_dei_file_in_git ] (master) $ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
mete_turistiche_dicembre.txt
nothing added to commit but untracked files present (use "git add" to track)
[ cancellare_dei_file_in_git ] (master) $ rm mete_turistiche_dicembre.txt
[ cancellare_dei_file_in_git ] (master) $ git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
Se invece il file che vogliamo eliminare è presente nella Staging Area, possiamo usare il comando git rm. Bisogna prestare attenzione perché il comando git rm non si limita a rimuovere un file dalla Staging Area, ma lo cancella anche dalla Working directory. Se vogliamo rimuovere un file solo dalla Staging Area possiamo usare l’opzione –cached.
Vediamo un esempio in cui abbiamo inizialmente il file mete_turistiche_dicembre.txt nella Working Area e nella Staging Area.
Se a questo punto eseguiamo il comando git rm –cached mete_turistiche_dicembre.txt, rimuoviamo il file dalla Staging Area.
# git status prima del comando git rm --cached
[ cancellare_dei_file_in_git ] (master ) $ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: mete_turistiche_dicembre.txt
# esecuzione del comando git rm --cached
[ cancellare_dei_file_in_git ] (master ) $ git rm --cached mete_turistiche_dicembre.txt
rm 'mete_turistiche_dicembre.txt'
# git status dopo l'esecuzione del comando git rm --cached
[ cancellare_dei_file_in_git ] (master ) $ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
mete_turistiche_dicembre.txt
nothing added to commit but untracked files present (use "git add" to track)
Partendo dallo stato corrente in cui il file mete_turistiche_dicembre.txt è nello stato Untracked, proviamo ad aggiungere nuovamente il file alla Staging Area e eseguiamo il comando git rm.
[ cancellare_dei_file_in_git ] (master ) $ git add mete_turistiche_dicembre.txt
[ cancellare_dei_file_in_git ] (master ) $ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: mete_turistiche_dicembre.txt
[ cancellare_dei_file_in_git ] (master ) $ git rm mete_turistiche_dicembre.txt
error: the following file has changes staged in the index:
mete_turistiche_dicembre.txt
(use --cached to keep the file, or -f to force removal)
Git ci avverte che il file è nella Staging Area, ma non è essendo stato aggiunto al repository, se eseguiamo git rm rischiamo di perdere il file per sempre visto che questo viene rimosso anche dalla Working Area. Se vogliamo comunque cancellarlo, dobbiamo usare l’opzione -f, altrimenti possiamo eseguire il commit e ripetere il comando git rm.
[ cancellare_dei_file_in_git ] (master ) $ git commit -m 'Aggiunge il file mete_turistiche_dicembre.txt'
[master (root-commit) a0ffe74] Aggiunge il file mete_turistiche_dicembre.txt
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 mete_turistiche_dicembre.txt
[ cancellare_dei_file_in_git ] (master ) $ git rm mete_turistiche_dicembre.txt
rm 'mete_turistiche_dicembre.txt'
# la cartella è ora vuota visto che il file
# mete_turistiche_dicembre.txt è stato cancellato dalla Working Area
[ cancellare_dei_file_in_git ] (master ) $ ls
Possiamo ora eseguire un nuovo commit, creando nel repository un nuovo snapshot nel quale salviamo le ultime modifiche subite dalla Working directory in seguito alla rimozione del file mete_turistiche_dicembre.txt.
[ cancellare_dei_file_in_git ] (master ) $ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: mete_turistiche_dicembre.txt
[ cancellare_dei_file_in_git ] (master ) $ git commit -m 'Cancella il file mete_turistiche_dicembre.txt'
Nell’immagine in alto abbiamo raffigurato con uno schema cosa succede dopo aver eseguito il commit. Abbiamo semplificato la rappresentazione del repository, mostrando solo lo stato dell’ultimo commit.
Rimuovere file Untracked dalla Working Directory
Il comando git clean può essere usato invece per rimuovere i file Untracked dalla Working Directory. Può risultare particolarmente utile quando sono presenti diversi file da rimuovere e non si vuole procedere manualmente. Vediamo un esempio in cui creiamo 10 file in una cartella che sono nello stato ‘Untracked’ non avendoli ancora aggiunti alla Staging Area.
[test_git_clean] (master) $ for i in {0..9}; do touch file_${i}; done
[test_git_clean] (master) $ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
file_0
file_1
file_2
file_3
file_4
file_5
file_6
file_7
file_8
file_9
nothing added to commit but untracked files present (use "git add" to track)
[test_git_clean] (master) $ git clean -n
Would remove file_0
Would remove file_1
Would remove file_2
Would remove file_3
Would remove file_4
Would remove file_5
Would remove file_6
Would remove file_7
Would remove file_8
Would remove file_9
Se eseguiamo il comando git clean con l’opzione -n o –dry-run, vengono elencati i file che verrebbero cancellati se lanciassimo il comando con l’opzione -f. Usando l’opzione -d vengono cancellate anche le cartelle ‘Untracked’.
[test_git_clean] (master) $ git clean -f
Removing file_0
Removing file_1
Removing file_2
Removing file_3
Removing file_4
Removing file_5
Removing file_6
Removing file_7
Removing file_8
Removing file_9
Spostare o rinominare dei file in Git
Vediamo ora un metodo per rinominare o spostare dei file in Git. Supponiamo di essere nella situazione in cui abbiamo all’interno di una cartella il file mete_turistiche_dicembre.txt che abbiamo precedentemente aggiunto alla Staging Area e al repository. Supponiamo di rinominare il file attraverso il comando mv come mostrato sotto.
[ rinominare_dei_file_in_git ] (master) $ mv mete_turistiche_dicembre.txt
mete_turistiche_gennaio.txt
[ rinominare_dei_file_in_git ] (master) $ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: mete_turistiche_dicembre.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
mete_turistiche_gennaio.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dopo aver rinominato il file, Git pensa che il vecchio file è stato cancellato e un nuovo file, ancora non aggiunto alla Staging Area, è stato creato. Procediamo col rimuovere dalla Staging Area il vecchio file.
[ rinominare_dei_file_in_git ] (master) $ git rm --cached mete_turistiche_dicembre.txt
rm 'mete_turistiche_dicembre.txt'
[ rinominare_dei_file_in_git ] (master) $ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: mete_turistiche_dicembre.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
mete_turistiche_gennaio.txt
A questo punto, ci sono delle modifiche pronte per essere inserite nel repository. Proseguiamo invece e aggiungiamo il file rinominato nella Staging Area.
[ rinominare_dei_file_in_git ] (master) $ git add mete_turistiche_gennaio.txt
[ rinominare_dei_file_in_git ] (master) $ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: mete_turistiche_dicembre.txt -> mete_turistiche_gennaio.txt
Git si accorge a questo punto che abbiamo sempicemente cambiato il nome del file e possiamo inserire nel repository un nuovo commit con il file appena rinominato.
[ rinominare_dei_file_in_git ] (master) $ git commit
-m 'Rinomina mete_turistiche_dicembre.txt in mete_turistiche_gennaio.txt'
[master 4255078] Rinomina mete_turistiche_dicembre.txt in mete_turistiche_gennaio.txt
1 file changed, 0 insertions(+), 0 deletions(-)
rename mete_turistiche_dicembre.txt => mete_turistiche_gennaio.txt (100%)
[ rinominare_dei_file_in_git ] (master) $ git status
On branch master
nothing to commit, working tree clean
Se la procedura appena vista può risultare lunga, possiamo usare il comando che Git mette a disposizione git mv <file> <nuovo_file>. Dovremo poi comunque effettuare il commit per salvare nel repository uno snapshot con le modifiche effettuate.
Primo contatto con il comando git checkout
Introduciamo il comando git checkout di cui riparleremo quando affronteremo l’argomento dei Branch. Tale comando può essere usato per diversi scopi. In questo caso vediamo due casi particolari. Vediamo innanzitutto come utilizzarlo per ripristinare un file dalla staging area nella working directory. Supponiamo di avere un file ciao.txt e aggiungiamolo alla Staging Area e poi al repository.
[ test_git_checkout ] (master) $ touch ciao.txt
[ test_git_checkout ] (master) $ git add .
[ test_git_checkout ] (master) $ git commit -m 'first commit'
[ test_git_checkout ] (master) $ echo ciao > ciao.txt
[ test_git_checkout ] (master) $ git add ciao.txt
[ test_git_checkout ] (master) $ echo 'ciao di nuovo' >> ciao.txt
Mostriamo con un’immagine lo stato corrente della Working Directory, della Staging Area e del Repository.
A questo punto eseguiamo il seguente comando:
[ test_git_checkout ] (master) $ git checkout -- ciao.txt
[ test_git_checkout ] (master) $ cat ciao.txt
ciao
Abbiamo così ripristinato nella working directory il file ciao.txt dalla Staging Area in cui è comunque rimasto lo stesso file, pronto per il prossimo commit.
Il simbolo ‘–‘ (doppio dash), usato nel comando git checkout, viene usato per convenzione per indicare a Git che quello che segue è il nome di un file e non il nome di un Branch. Infatti, come vedremo possiamo usare git checkout per spostarci da un Branch all’altro.
Un’altra possibilità fornita da git checkout è quella di ripristinare nella working directory e nella staging area il contenuto di un determinato file salvato all’interno di un commit del repository.
$ git checkout <commit> elenco_file
Git copierà i file passati come argomento dal commit specificato all’interno della staging area e working directory.
Facendo riferimento all’immagine sopra, il comando lanciato potrebbe essere simile a quello riportato sotto.
$ git checkout 39d73 file.js
Avremmo potuto anche usare il riferimento HEAD al posto di un commit.
# esempio
$ git checkout HEAD file.js
In quest’ultimo caso verrebbe ripristinato il valore del file.js dall’ultimo commit del repository, ovvero quello a cui punta il branch master referenziato da HEAD.
Correggere l’ultimo commit con git commit –amend
Il comando git commit con l’opzione –amend permette di modificare l’ultimo commit. Può capitare infatti di voler creare un unico commit che comprenda i file presenti nell’ultimo e quelli aggiunti successivamente alla Staging Area. Oppure può essere necessario modificare per qualche motivo il messaggio dell’ultimo commit. Vediamo un esempio in cui creiamo un file ciao.txt che aggiungiamo nel repository.
$ echo ciao > ciao.txt
$ git add .
$ git commit -m 'Aggiunge un file'
[master (root-commit) 2122c0e] Aggiunge un file
1 file changed, 1 insertion(+)
create mode 100644 ciao.txt
$ git log --oneline
2122c0e (HEAD -> master) Aggiunge un file
Supponiamo a questo punto di creare un nuovo file hello.txt e di volerlo incorporare nello stesso commit del file precedente. Modifichiamo inoltre il messaggio dell’ultimo commit.
$ echo hello > hello.txt
$ git add .
$ git commit --amend -m 'Aggiunge i file ciao.txt e hello.txt'
[master 7fa2a92] Aggiunge i file ciao.txt e hello.txt
2 files changed, 2 insertions(+)
create mode 100644 ciao.txt
create mode 100644 hello.txt
$ git log --oneline
7fa2a92 (HEAD -> master) Aggiunge i file ciao.txt e hello.txt
# git ls-tree elenca il contenuto di un oggetto di tipo Tree
# in questo caso elenca il contenuto dell'oggetto Tree a cui punta il commit
$ git ls-tree 7fa2a92
100644 blob 887ae9333d92a1d72400c210546e28baa1050e44 ciao.txt
100644 blob ce013625030ba8dba906f756967f9e9ca394464a hello.txt
Ricordiamo che ogni commit è identificato da un valore di hash univoco. Per questo motivo non è possibile modificare il vecchio commit, ma ne viene creato uno nuovo contenente entrambi i file. Il vecchio commit sarà poi eliminato dal garbage collector dopo un certo lasso di tempo.
Concludiamo dicendo che è anche possibile usare l’opzione –no-edit se si vogliono apportare le modifiche senza cambiare il messaggio del commit.
Conclusioni
In questa lezione abbiamo visto come cancellare dei file in git con i comandi git rm e git clean. Abbiamo poi illustrato come spostare o rinominare un file. Abbiamo mostrato un possibile uso del comando git checkout e infine abbiamo visto come correggere l’ultimo commit effettuato attraverso l’opzione –amend del comando git commit. Nella prossima lezione vedremo quali strumenti vengono messi a disposizione da Git per far in modo che un file non venga tracciato e quindi venga ignorato da Git stesso.