Se dovessimo provare a spostare un file come normalmente siamo abituati a fare, Git non la prenderebbe molto bene.
1$ git status
2On branch master
3Changes not staged for commit:
4 (use "git add/rm <file>..." to update what will be committed)
5 (use "git restore <file>..." to discard changes in working directory)
6 deleted: lorem.txt
7
8Untracked files:
9 (use "git add <file>..." to include in what will be committed)
10 documenti-importanti/lorem.txt
11
12no changes added to commit (use "git add" and/or "git commit -a")
Il file che abbiamo spostato nel mio caso lorem.txt
verrebbe indicato come cancellato, mentre un nuovo file untracked verrebbe aggiunto, il mio file nella sua nuova destinazione. MA attenzione! È tutto normale.
Cerchiamo di comprendere meglio la faccenda comprendendo sin da subito che
Non esiste lo spostamento o la rinomina in Git
Senza troppi giri di parole questa è la cruda realtà. Git per quanto metta a disposizione un comando per lo spostamento/rinomina, non fa niente di tutto questo.
A Git interessano solo i file che sono stati aggiunti o cancellati e ricorda che Git ragiona in base al contenuto del file più che al suo nome.
Per essere ancora più precisi sulla faccenda, Git, in nessun momento, memorizza il fatto che un file è stato rinominato in qualcos’altro. Nel database di versionamento l’unica cosa che vedremo è che il file lorem.txt è stato cancellato e il file lorem.txt dentro la directory documenti-importanti è stato creato. Fine.
Ciò comporta, se non vi fosse ancora venuto in mente, che dopo una rinomina o uno spostamento perderete la cronologia delle modifiche del file.
Ora capirete perché quindi la reazione di Git allo spostamento non era poi così esagerata, ma del tutto in linea con il modo in cui Git stesso opera, se vi state chiedendo il perché, il motivo è legato semplicemente alle performance, ogni tanto per poter garantire l’efficienza di un sistema bisogna fare delle scelte e perdere la cronologia delle modifiche di un file rinominato o spostato è una di quelle. Alcuni diranno che è un enorme problema, ma ci sono modi e modi di fare le cose e tra questi ci sono quelli intelligenti e quelli sbagliati.
Il motivo della scelta lo potete trovare qui
Il comando git mv
Parto subito con lo scrivere che il comando in questione non è il metodo intelligente, quello lo vedremo tra poco. git mv
è il comando che ci permette di spostare/rinominare un file, ma attenzione perché non è altro che una scorciatoia.
Già perché quando noi eseguiamo git mv
, cosa accade?
1$ git mv lorem.txt documenti-importanti
2$ git status
3On branch master
4Changes to be committed:
5 (use "git restore --staged <file>..." to unstage)
6 renamed: lorem.txt -> documenti-importanti/lorem.txt
Git status ci dice che il file lorem.txt è stato rinominato, ma ricorda quello che ho scritto prima: in nessun momento, Git, memorizza il fatto che un file è stato rinominato in qualcos’altro.
git mv
esegue due comandi: git rm
e git add
, niente di più e niente di meno.
Ciò significa che volendo possiamo ottenere gli stessi medesimi risultati anche spostando i file con dei comandi di sistema (o anche un ancora più semplice drag & drop):
1$ mv lorem.txt document-importanti
2$ git add documenti-importanti/lorem.txt
3$ git rm lorem.txt
4rm ‘lorem.txt’
5$ git status
6On branch master
7Changes to be committed:
8 (use "git restore --staged <file>..." to unstage)
9 renamed: lorem.txt -> documenti-importanti/lorem.txt
In Windows, da prompt dei comandi o powershell il comando equivalente di mv
è move
.
Morale della favola, se volete spostare centinaia di file ed essere certi che Git abbia compreso che si tratta di una rinomina non c’è bisogno di eseguire centinaia di git mv
. Il risultato sarà identico ad uno spostamento fatto manualmente da filesystem.
Se spostate centinaia di file, Git sarà velocissimo a comprendere che si tratta di rinomine al posto di centinaia di centinaia di cancellazioni e centinaia di aggiunte. Questo perché l’hash del file, che si basa sul contenuto del file, non cambia.
Mai spostare e modificare allo stesso tempo
Questa è una best practice che si usa quando bisogna fare dei lavori di ristrutturazione della repository.
La regola di base è semplice: non spostare/rinominare e fare dei cambiamenti nello stesso momento.
Se vuoi cambiare la struttura (rinominando e spostando i file):
- Crea una nuova branch
- Fai le rinomine e gli spostamenti che devi fare (senza fare cambiamenti a livello di contenuto)
- Fai le commit
- Fai il merge o crea una pull request
Se vuoi invece cambiare il contenuto dei file:
- Crea una nuova branch
- Fai le modifiche che devi fare (senza fare cambi di nome o spostamenti)
- Fai le commit
- Fai il merge o crea una pull request
In questo modo, ed è l’unico modo, potremo sempre accedere alla cronologia delle modifiche di un file anche se è stato rinominato o spostato.
Conclusioni
Chiarito questo mistero sulle rinomine e gli spostamenti possiamo andare oltre e finalmente approfondire una volta per tutte le branch.
Caricamento...
Diventiamo amici di penna? ✒️
Iscriviti alla newsletter per ricevere una mail ogni paio di settimane con le ultime novità, gli ultimi approfondimenti e gli ultimi corsi gratuiti puubblicati. Ogni tanto potrei scrivere qualcosa di commerciale, ma solo se mi autorizzi, altrimenti non ti disturberò oltre.
Se non ti piace la newsletter ti ricordo la community su Discord, dove puoi chiedere aiuto, fare domande e condividere le tue esperienze (ma soprattutto scambiare due meme con me). Ti aspetto!