Guida

git stash: come mettere da parte le modifiche e recuperarle

Aggiornato: · Skillaria.Top

git stash sposta le modifiche non committate in un archivio separato e riporta la cartella di lavoro all'ultimo commit, così potete passare a un altro compito. Per recuperarle usate git stash pop (applica ed elimina dall'archivio) o git stash apply (applica e conserva); un comando git unstash non esiste.

A cosa serve git stash

Situazione tipica: siete a metà di un lavoro, i file sono modificati, è troppo presto per un commit, e arriva la richiesta di correggere con urgenza un bug su un altro branch. Cambiare branch non si può, oppure temete di perdere le modifiche. git stash mette «in tasca» tutte le modifiche non committate e riporta la cartella di lavoro allo stato dell'ultimo commit.

$ git stash
Saved working directory and index state WIP on feature/login: 3f2a1c4 Form di accesso

$ git status
On branch feature/login
nothing to commit, working tree clean

Ora potete cambiare branch, correggere il bug, tornare indietro e recuperare ciò che avete messo da parte. Ogni salvataggio è una voce nello stack dello stash; internamente Git la conserva come un commit speciale, quindi i dati sono al sicuro e non dipendono dal branch.

Come salvare le modifiche: le opzioni principali

Con una descrizione chiara

La descrizione predefinita «WIP on branch» tra una settimana non vi dirà nulla. Aggiungete un messaggio:

git stash push -m "validazione form, e-mail da finire"

git stash senza argomenti è un'abbreviazione di git stash push. La vecchia forma git stash save "messaggio" funziona ancora, ma negli script nuovi usate push -m.

Insieme ai file nuovi

Per impostazione predefinita lo stash prende solo i file tracciati: quelli modificati e quelli aggiunti all'index. I file nuovi, mai passati per git add, restano nella cartella di lavoro. È una sorpresa frequente.

git stash -u        # --include-untracked: anche i file non tracciati
git stash -a        # --all: anche i file in .gitignore

Attenzione con -a: in tasca finiscono anche node_modules, le build e le configurazioni locali. Di solito basta -u.

Solo una parte delle modifiche

git stash push -m "config" src/config.js   # solo i file indicati
git stash -p                                # scegliere i frammenti in modo interattivo
git stash --staged                          # solo ciò che è nell'index (Git 2.35+)
git stash --keep-index                      # mettere da parte tutto, ma lasciare l'index nella cartella

--keep-index è utile prima di un commit: lasciate nella cartella di lavoro solo ciò che intendete committare, eseguite i test e verificate che il commit sia autosufficiente.

Come recuperare le modifiche (git unstash)

Il comando git unstash in Git non esiste: di solito è così che si cerca il modo di recuperare ciò che si è messo da parte. Per farlo ci sono due comandi.

ComandoCosa faVoce nello stack
git stash popApplica le ultime modifiche messe da parteViene eliminata, se applicata senza conflitti
git stash applyApplica le ultime modifiche messe da parteResta
git stash pop stash@{2}Applica una voce specificaViene eliminata
git stash apply --indexRipristina anche la divisione tra index e cartella di lavoroResta
$ git stash pop
On branch feature/login
Changes not staged for commit:
        modified:   src/auth.js
        modified:   src/form.js
Dropped refs/stash@{0} (8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d)

Notate che, per impostazione predefinita, anche ciò che era nell'index al momento dello stash torna come normale modifica. Se vi serve conservare l'index preparato, aggiungete --index.

pop o apply

Nel lavoro di tutti i giorni è comodo pop: recuperate e dimenticate. Scegliete apply quando volete applicare le stesse modifiche su più branch o non siete sicuri che tutto vada liscio: la voce resta come garanzia e potete eliminarla in seguito con git stash drop.

Gestire la lista delle voci

$ git stash list
stash@{0}: On feature/login: validazione form, e-mail da finire
stash@{1}: WIP on main: 9b7e0d2 Aggiorna le dipendenze
stash@{2}: On feature/api: esperimento con la cache

Lo stack segue il principio «l'ultimo entrato è il primo a uscire»: stash@{0} è sempre la voce più recente, e i numeri scorrono dopo ogni push e drop.

ComandoScopo
git stash showStatistiche sintetiche delle modifiche dell'ultima voce
git stash show -p stash@{1}Diff completo di una voce specifica
git stash drop stash@{1}Eliminare una voce
git stash clearEliminare tutte le voci in una volta
git stash branch nome stash@{0}Creare un branch dal commit su cui è stato fatto lo stash, applicare la voce ed eliminarla

Perché git stash show mostri per impostazione predefinita il diff completo invece delle statistiche, e insieme i file non tracciati, esistono le impostazioni stash.showPatch e stash.showIncludeUntracked.

Scenario passo passo: un bug urgente a metà lavoro

  1. Mettete da parte il lavoro corrente insieme ai file nuovi: git stash push -u -m "login: bozza".
  2. Passate al branch principale e create un branch per la correzione: git switch main, git pull, git switch -c hotfix/null-email.
  3. Correggete l'errore, fate il commit, inviatelo in review.
  4. Tornate al vostro compito: git switch feature/login.
  5. Recuperate le modifiche: git stash pop. Controllate con git status: è tutto al suo posto.

Oggi molti per questo scenario usano git worktree: una seconda cartella di lavoro per lo stesso repository permette di non mettere da parte nulla. Ma per un cambio rapido di cinque minuti lo stash resta più semplice.

Conflitti quando si applica uno stash

Se dopo lo stash le stesse righe sono cambiate nel branch, l'applicazione terminerà con un conflitto:

$ git stash pop
Auto-merging src/auth.js
CONFLICT (content): Merge conflict in src/auth.js
The stash entry is kept in case you need it again.

In questo caso la voce non viene eliminata, nemmeno con pop. Risolvete il conflitto nel file come di consueto, poi eseguite git add per segnare la risoluzione (oppure git restore --staged se non volete lasciare le modifiche nell'index) ed eliminate la voce ormai inutile con git stash drop.

Se il conflitto è complicato, conviene una scorciatoia: git stash branch tmp-login. Git creerà un branch proprio dal commit su cui avevate fatto lo stash: lì le modifiche si applicano senza conflitti, e poi le unirete al branch principale con un normale merge.

Come recuperare uno stash eliminato per errore

Avete eseguito git stash drop o clear per sbaglio? Non tutto è perduto. La voce era un commit, e finché il garbage collector non lo rimuove, si può trovare tra gli oggetti «orfani» (dangling):

git fsck --no-reflog | grep "dangling commit"
git show 8c1d2e3        # verificare che sia lo stash giusto
git stash apply 8c1d2e3

Se avete appena eliminato la voce con drop o pop, l'hash è stampato direttamente nell'output del comando, nella riga Dropped refs/stash@{0} (...). Basta passarlo a git stash apply.

Come funziona lo stash internamente

Capire com'è fatto toglie la paura di perdere dati. Ogni voce dello stash è un normale commit a cui punta il riferimento refs/stash. Ha due genitori: il commit HEAD su cui vi trovavate e un commit separato con lo stato dell'index. Con -u si aggiunge un terzo genitore con i file non tracciati. La lista stash@{N} è semplicemente il registro (reflog) del riferimento refs/stash.

Ne derivano alcune conseguenze pratiche. Uno stash si può passare a qualsiasi comando che accetti un commit: git diff stash@{0}, git show stash@{0}:src/auth.js (il contenuto di un singolo file della voce) oppure git checkout stash@{0} -- src/auth.js per recuperare un solo file senza applicare tutta la voce. E una voce eliminata resta nel database degli oggetti finché la garbage collection non la rimuove.

Lo stash e gli altri comandi Git

Alcuni comandi sanno mettere da parte le modifiche da soli. git rebase --autostash e git pull --rebase --autostash prima di iniziare accantonano le modifiche non committate e le ripristinano alla fine. Potete attivare questo comportamento in modo permanente con le impostazioni rebase.autoStash true e merge.autoStash true. Se al ripristino si verifica un conflitto, Git conserverà la voce nel normale stack dello stash e ve lo segnalerà.

Anche il cambio di branch con git switch non sempre richiede lo stash: se le vostre modifiche non toccano i file che differiscono tra i branch, Git semplicemente le porterà con sé. Lo stash serve quando Git risponde «Your local changes would be overwritten by checkout» o quando non volete portarvi le modifiche in un altro branch.

Errori comuni

  • I file nuovi «non sono finiti nello stash». Non sono tracciati, serve -u.
  • Lo stash come archivio a lungo termine. Dopo un mese nella lista ci sono dieci «WIP on main» senza nome e nessuno ricorda cosa contengano. Per un lavoro lungo fate un commit su un branch separato: almeno si può fare push.
  • Dimenticare che la voce è rimasta dopo un conflitto e applicarla di nuovo tempo dopo. Dopo aver risolto un conflitto fate sempre drop.
  • Lo stash non si sincronizza con il server. Esiste solo nel vostro repository locale, git push non lo invia. Se cancellate la cartella del progetto, lo stash sparisce.
  • Applicare la voce sbagliata. Prima di pop controllate git stash list e git stash show -p.

In sintesi

git stash è un modo rapido per liberare la cartella di lavoro senza perdere le modifiche non committate: git stash push -u -m "descrizione" per metterle da parte e git stash pop per recuperarle. Usate apply quando vi serve una garanzia, git stash list e show -p per non confondervi, e non trasformate lo stash in un magazzino: per tutto ciò che dura a lungo ci sono commit e branch. Il passaggio da un compito all'altro con lo stash si esercita nella pratica nel corso su Git.

Domande frequenti

Si può applicare uno stash su un altro branch?

Sì, lo stash non è legato a un branch: passate a quello desiderato ed eseguite git stash pop o apply. Se le modifiche non si sovrappongono correttamente, si avrà un normale conflitto.

git stash salva le modifiche nell'index?

Sì, ma con un normale pop o apply tutto torna come modifiche non preparate. Per ripristinare anche l'index usate git stash apply --index.

Quante voci si possono tenere nello stash?

Non c'è un limite rigido, ma le voci più vecchie del periodo di conservazione del reflog possono essere eliminate dalla garbage collection. In pratica tenete nello stack al massimo un paio di voci recenti.

Come si fa lo stash di un solo file?

Indicate il percorso dopo due trattini o direttamente dopo push: git stash push -m descrizione -- src/config.js. Nello stash finirà solo quel file, le altre modifiche resteranno nella cartella di lavoro.

Che differenza c'è tra lo stash e un commit temporaneo?

Il commit vive in un branch, si può inviare al server e poi correggere con amend o rebase. Lo stash è conservato solo in locale in uno stack separato ed è comodo per cambi rapidi.

Impara l’argomento in video

Questo argomento è trattato in modo approfondito, con pratica, nel corso «Git da zero a sviluppatore sicuro».

Vai al corso