Full Stack

Come spostare un file in Git

Autore

Manuel Ricci

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):

  1. Crea una nuova branch
  2. Fai le rinomine e gli spostamenti che devi fare (senza fare cambiamenti a livello di contenuto)
  3. Fai le commit
  4. Fai il merge o crea una pull request

Se vuoi invece cambiare il contenuto dei file:

  1. Crea una nuova branch
  2. Fai le modifiche che devi fare (senza fare cambi di nome o spostamenti)
  3. Fai le commit
  4. 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!

Ho in previsione di mandarti una newsletter ogni due settimane e una commerciale quando capita.