Durante lo sviluppo, può capitare di voler annullare una modifica o correggere un errore. Git offre diversi strumenti per gestire queste situazioni, ma è fondamentale utilizzarli con cautela: alcune operazioni di undo non sono reversibili e, se usate in modo improprio, possono comportare la perdita definitiva di lavoro.
Correggere l’ultimo commit con --amend
Uno degli scenari più comuni si verifica quando si effettua un commit troppo presto, dimenticando di includere un file o inserendo un messaggio di commit errato. In questi casi, Git consente di sostituire l’ultimo commit con uno nuovo tramite l’opzione --amend:
git commit --amend
Git prende il contenuto dell’area di staging (index) e lo utilizza per generare un nuovo commit.
Se non sono state aggiunte nuove modifiche dallo scorso commit, verrà riaperto semplicemente l’editor dei messaggi di commit, consentendo di modificarlo.
Esempio pratico
Supponiamo di aver eseguito il commit e di esserci resi conto di aver dimenticato di inserire le modifiche in un file che volevamo aggiungere a questo commit. Possiamo rimediare aggiungendo il file con git add e rieseguire il commit con git commit --amend:
git add file_dimenticato
git commit --amend
Il repository avrà un solo commit, che include anche file_dimenticato. Il commit precedente viene sovrascritto e sparisce dalla cronologia.
- Sostituzione, non modifica
- Amend non aggiorna un commit già esistente ma lo sostituisce con un nuovo commit dotato di un nuovo identificativo (SHA-1).
- Di fatto, è come se il commit precedente non fosse mai esistito. - Pulizia della cronologia
- L’opzione --amend è utile per evitare commit ridondanti. - Limitazione: solo commit locali
- È fortemente sconsigliato eseguire git commit --amend su commit già pubblicati (pushed) in un repository remoto. Infatti, l’operazione riscrive la cronologia e, se accompagnata da un git push --force, può creare conflitti e problemi per gli altri collaboratori.
git commit --amend
Scenario | Comando | Risultato |
---|---|---|
Modificare solo il messaggio di commit | git commit --amend (senza nuovi file in staging) | Sovrascrive il messaggio dell’ultimo commit |
Aggiungere file dimenticati | git add file + git commit --amend | Crea un nuovo commit che sostituisce il precedente includendo anche file |
Commit già pushato sul remoto | git commit --amend + git push --force | Sconsigliato: riscrive la cronologia e può rompere il lavoro dei collaboratori |
Rimuovere un File dall’Area di Staging
Durante il lavoro quotidiano con Git, può capitare di inserire per errore più file nell’area di staging (index) utilizzando un comando troppo generico, come ad esempio:
git add *
In questo caso, se l’obiettivo era committare i file separatamente, è necessario rimuovere uno o più file dallo staging (unstaging), riportandoli allo stato di semplici modifiche nella working directory.
A partire dalla versione 2.23.0, Git ha introdotto il comando git restore, concepito come alternativa più intuitiva e leggibile rispetto a git reset per alcune operazioni di annullamento (undo).
L’obiettivo di questo nuovo comando è semplificare la sintassi e ridurre i rischi legati a usi impropri di git reset, che in passato potevano facilmente portare alla perdita involontaria di dati.
la differenza principale tra git restore e git reset HEAD sta nel loro scopo e nell'ambito d'azione:
- git restore è un comando moderno e più sicuro, ideato per ripristinare i file nello stato in cui si trovavano in una versione precedente. Agisce sulla working directory (area di lavoro) o sulla staging area (area di "preparazione" prima del commit), ma non modifica la cronologia dei commit. È l'ideale per annullare modifiche locali, che non sono ancora state salvate nella cronologia.
- git reset HEAD è un comando più vecchio, versatile e potente, che agisce primariamente sulla cronologia dei commit. Sposta il puntatore HEAD a un commit precedente, e di conseguenza, può influenzare l'area di staging e l'area di lavoro a seconda dell'opzione utilizzata (--soft, --mixed, o --hard). È uno strumento più "distruttivo" e va usato con cautela, specialmente su branch condivisi, perché modifica la storia del repository.
Identificare i file in staging con git status
Il comando git status non solo mostra lo stato della working directory e dell’area di staging, ma fornisce anche indicazioni utili su come annullare operazioni indesiderate.
Esempio pratico:
Per individuare il file da rimuovere all'area di staging
![]() |
FIG 1 - git status |
Come si può notare da FIG 1 , Git suggerisce direttamente il comando corretto per rimuovere un file dallo staging.
git restore --staged <file>
Nel nostro caso, per rimuovere il file main.cs dallo staging il comando sarà
git restore --staged main.cs
![]() |
FIG 2 - git restore --staged |
Lo stesso risultato lo si ottiene con
git reset HEAD <file>
Il comando git reset è spesso considerato pericoloso, poiché con opzioni come --hard può portare alla perdita definitiva di modifiche locali. Tuttavia, in questo scenario, l’uso di git reset HEAD è sicuro perché non modifica i contenuti della working directory ma agisce esclusivamente sull’indice, rimuovendo il file dallo staging.
Comando | Effetto |
---|---|
git add file | Aggiunge un file all’area di staging |
git reset HEAD file | Rimuove il file dallo staging, mantenendo le modifiche nella working directory |
git restore --staged file | Alternativa moderna a git reset HEAD file , con la stessa funzione |
git reset --hard | Pericoloso: annulla anche le modifiche nella working directory |
Annullare le modifiche a un File
Può capitare di accorgersi che le modifiche apportate a un file non sono più necessarie e che si desidera ripristinare il contenuto all’ultima versione tracciata da Git (ossia l’ultima presente nell’area di staging o nel commit più recente).
In questi casi, Git mette a disposizione due comandi storicamente equivalenti, ma con differenze importanti: git restore (introdotto in Git ≥ 2.23.0) e git checkout (metodo tradizionale).
Esempio pratico con git restore
Supponiamo di aver modificato il file main.cs. Eseguiamo il comando
git status
![]() |
FIG 3 - git status |
Per annullare le modifiche non salvate:
git restore main.cs
Dopo il comando, il file torna allo stato dell’ultimo commit o staging, eliminando definitivamente i cambiamenti locali.
![]() |
FIG 4 - git restore |
Esempio pratico con git checkout
git checkout -- main.cs
Anche in questo caso il file viene ripristinato, cancellando le modifiche locali.
![]() |
FIG 5 - git checkout |
git restore
e git checkout
Caratteristica | git restore | git checkout |
---|---|---|
Disponibilità | Introdotto in Git ≥ 2.23.0 | Presente in tutte le versioni di Git |
Obiettivo | Progettato specificamente per annullare modifiche ai file (working directory e staging) | Comando multifunzione (cambio branch, ripristino file, navigazione) |
Chiarezza sintattica | Più leggibile e autoesplicativo (restore indica chiaramente lo scopo) | Sintassi più generica e meno intuitiva |
Rischio di confusione | Ridotto: il comando è dedicato solo al ripristino | Elevato: git checkout gestisce operazioni molto diverse tra loro |
Best Practice | Consigliato nei workflow moderni per annullare modifiche locali | Ancora valido, ma da usare con cautela per evitare ambiguità |
Attenzione
- Entrambi i comandi cancellano in modo irreversibile le modifiche locali non ancora salvate in un commit.
- Prima di utilizzarli, è opportuno chiedersi se le modifiche possano essere utili in futuro.
- In alternativa, si può ricorrere a git stash o a un nuovo branch, salvando temporaneamente i cambiamenti senza perderli.
È importante ricordare che soltanto ciò che è stato effettivamente sottoposto a commit può essere recuperato; le modifiche non salvate andranno invece perse in maniera definitiva.
In Git, i dati oggetto di commit risultano quasi sempre recuperabili, anche qualora appartengano a rami successivamente eliminati oppure siano stati sovrascritti tramite l’opzione --amend. Tutte le modifiche non ancora committate e andate perse non potranno, con ogni probabilità, essere ripristinate.
Best Practice
- Usare git restore nei progetti moderni: più chiaro e meno soggetto a errori.
- Evitare git checkout -- <file> se non strettamente necessario: mantiene la retrocompatibilità, ma può confondere.
- Ricorrere a git stash o ai branch per soluzioni temporanee: ideale se non si vuole perdere il lavoro fatto.
Nessun commento:
Posta un commento
I messaggi sono soggetti a moderazione da parte dell'amministratore prima della loro pubblicazione.