W3docs

git reflog

Informazioni dettagliate sul comando git reflog: riferimenti, sottocomandi, reflog temporali ed esempi pratici di recupero dei commit.

Il comando git reflog è la tua rete di sicurezza. Registra ogni modifica apportata ai riferimenti locali — branch, HEAD e stash — così puoi recuperare commit che sembrano essere scomparsi dopo un reset, un rebase, un amend o l'eliminazione di un branch. Questa pagina spiega cosa conserva il reflog, come leggere la sintassi name@{n}, come filtrare le voci per tempo, i sottocomandi disponibili e una guida completa per recuperare i commit "perduti".

Cos'è il reflog

Un riferimento (o "ref") è un puntatore a un commit — HEAD, la punta di un branch come main, o una voce dello stash. Molte operazioni Git spostano questi puntatori: ogni git commit, checkout, merge, rebase o reset aggiorna il punto verso cui punta un ref. Il reflog ("reference log") registra quella cronologia degli spostamenti.

Questo è importante perché Git quasi mai elimina i commit immediatamente. Quando un'operazione come un hard reset o un rebase rende un commit irraggiungibile da qualsiasi branch o tag, l'oggetto commit vive ancora nel repository e il reflog mantiene ancora un puntatore ad esso. Finché quella voce del reflog esiste, puoi recuperare il commit.

git reflog

Informazione

Il reflog è strettamente locale e specifico per ogni clone. Non viene mai inviato né scaricato, quindi un clone appena creato ha un reflog vuoto. Se riscrivi la cronologia e perdi un commit, puoi recuperarlo solo dal computer su cui è stato eseguito il lavoro.

Utilizzo di base

La forma più semplice non richiede argomenti:

git reflog

È una scorciatoia per visualizzare il reflog di HEAD:

git reflog show HEAD

L'output elenca ogni posizione in cui si trovava HEAD, dalla più recente alla più vecchia:

a32556a HEAD@{0}: commit: migrating content
ab371fd HEAD@{1}: commit: adding git reflog outline
23a491a HEAD@{2}: checkout: moving from stage to feature/solver
7b119cb HEAD@{3}: checkout: moving from feature/solver to stage
56a183a HEAD@{4}: commit: changing color scheme
7a2aa71 HEAD@{5}: commit: adding more color palettes
a56322b HEAD@{6}: commit: adding color tool package

Ogni riga si legge in tre parti:

  • a32556a — l'hash abbreviato del commit a cui puntava HEAD.
  • HEAD@{0} — il selettore del reflog. @{0} è la posizione più recente, @{1} quella precedente, e così via, contando all'indietro nel tempo.
  • commit: migrating content — l'azione che ha spostato il ref, con il suo messaggio.

L'etichetta dell'azione indica come si è spostato il ref (commit, checkout, merge, rebase -i, reset), rendendo il reflog leggibile come una cronologia passo-passo di ciò che hai fatto localmente.

Riferimenti del reflog

Per impostazione predefinita git reflog mostra il reflog di HEAD, che segue qualsiasi branch sia attualmente estratto. Ma ogni ref mantiene il proprio reflog, accessibile con la sintassi name@{qualifier}.

Per vedere il reflog di tutti i riferimenti contemporaneamente:

git reflog show --all

Passa il nome di un branch per esaminare solo la cronologia di quel branch. Di seguito, il reflog per test_branch:

git reflog show test_branch
32a591f test_branch@{0}: commit: add snippets
23bae4a test_branch@{1}: commit (initial): initial commit

Nota la differenza: HEAD@{1} significa "dove si trovava HEAD un movimento fa," mentre test_branch@{1} significa "dove si trovava test_branch stesso un movimento fa." Questa distinzione è ciò che permette di recuperare la punta di un branch che un hard reset o un aggiornamento forzato ha spostato.

Puoi anche leggere il reflog per git stash:

git reflog stash
0d44de3 stash@{0}: WIP on git_reflog: a567574 adding Vue.js

Reflog temporali

Ogni voce del reflog ha un timestamp allegato. Questi possono essere utilizzati come qualificatori nella sintassi dei puntatori Git, permettendo di filtrare i reflog Git per tempo. Ecco alcuni esempi di qualificatori temporali:

  • 1.minute.ago
  • 1.hour.ago
  • 1.day.ago
  • yesterday
  • 1.week.ago
  • 1.month.ago
  • 1.year.ago
  • 2011-05-17.09:00:00

Puoi combinare i qualificatori (ad es. 1.week.3.hours.ago) e usare le forme plurali (ad es. 5.hours.ago). Un ref con qualificatore temporale può essere passato ad altri comandi Git, non solo a git reflog:

git diff master@{0} master@{1.week.ago}

Mostra una diff del master attuale rispetto a dove puntava master una settimana fa.

Attenzione

Un qualificatore temporale si risolve rispetto al reflog, non alle date dei commit. master@{1.week.ago} significa "il commit a cui faceva riferimento master una settimana fa su questa macchina," che può differire da "il commit creato una settimana fa." Su un clone appena creato senza cronologia nel reflog, Git torna alla punta corrente e potrebbe avvertire che il log è troppo breve.

Sottocomandi di git reflog

Git reflog accetta diversi argomenti che fungono da sottocomandi. Di seguito sono descritti.

git reflog show

git reflog show è il comportamento predefinito ed è esso stesso un alias per git log -g --abbrev-commit --pretty=oneline. Questi due comandi sono equivalenti:

git reflog master@{0}
git reflog show master@{0}

git reflog expire

git reflog expire elimina le voci del reflog vecchie o irraggiungibili. Poiché la rimozione delle voci può rendere i commit genuinamente irrecuperabili, raramente lo si esegue manualmente — Git lo esegue automaticamente durante git gc. Per impostazione predefinita le voci raggiungibili scadono dopo 90 giorni (gc.reflogExpire) e quelle irraggiungibili dopo 30 giorni (gc.reflogExpireUnreachable). Per forzare una scadenza personalizzata:

git reflog expire --expire=1.day.ago --all

git reflog delete

git reflog delete rimuove una specifica voce del reflog tramite il suo selettore. Come expire, comporta un rischio reale di perdita della recuperabilità ed è raramente necessario nel lavoro quotidiano:

git reflog delete HEAD@{1}
Pericolo

Una volta che una voce del reflog scade o viene eliminata, il commit a cui puntava diventa veramente irraggiungibile e sarà rimosso la prossima volta che viene eseguito git gc. Tratta expire e delete come strumenti di pulizia, non come strumenti di annullamento.

Recupero dei commit perduti

I commit non sono mai veramente persi in Git, nemmeno durante le operazioni di riscrittura della cronologia — e il reflog è il modo per recuperarli. Supponiamo che git log --pretty=oneline mostri questo:

2b43ceab309da94256db8fb1f35b1678fb74abd4 changes in content
c32557493a95185997c87e0bc3a9481715279351 adding Vue.js
abc234f986d270d7f97c77618314a06f024c4563 migrating content
a5673cd762d8ef2e146d7f0226e81a92f91956b1 adding git reflog outline
2bce4a4404c42128bee8468a9517418ed0ea412 initial commit

Ora supponiamo di eseguire il commit di alcune nuove modifiche in questo repository:

# make changes to HEAD
git commit -am "API changes"

Il log ora appare così:

37656e19d4e4f1a9b419f57850c8f1974f871b07 API changes
2b43ceab309da94256db8fb1f35b1678fb74abd4 changes in content
c32557493a95185997c87e0bc3a9481715279351 adding Vue.js
abc234f986d270d7f97c77618314a06f024c4563 migrating content
a5673cd762d8ef2e146d7f0226e81a92f91956b1 adding git reflog outline
2bce4a4404c42128bee8468a9517418ed0ea412 initial commit

Successivamente avviamo un rebase interattivo su master:

git rebase -i origin/master

Durante il rebase contrassegniamo i commit con l'azione s (squash) per unirli al commit "API changes" più recente. Successivamente l'output di git log è ridotto a:

40d8a1237656e19d4e4f1a9b419f57850c8f1974 API changes
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit

I commit uniti sembrano spariti. Ma il reflog registra ancora ogni posizione in cui si trovava HEAD durante il rebase:

git reflog
37656e1 HEAD@{0}: rebase -i (finish): returning to refs/heads/git_reflog
37656e1 HEAD@{1}: rebase -i (start): checkout origin/master
37656e1 HEAD@{2}: commit: API changes

HEAD@{2} è lo stato appena prima dell'inizio del rebase. Passa quel selettore a git reset per tornare ad esso:

git reset --hard HEAD@{2}

Questo sposta HEAD al commit "API changes" precedente al rebase e ripristina tutti i commit uniti. Usa --hard per reimpostare anche la directory di lavoro a quello stato, oppure omettilo (git reset HEAD@{2}) per spostare solo il puntatore del branch mantenendo i file attuali.

Quando usare git reflog

Ricorri al reflog ogni volta che un ref si è spostato e vuoi recuperarlo:

  • Dopo un git reset --hard che ha scartato commit di cui in realtà avevi bisogno.
  • Per recuperare commit orfani da un rebase interattivo, un amend o uno squash.
  • Per ripristinare un branch eliminato con git branch -D (trova la sua ultima punta nel reflog, poi git branch <name> <hash>).
  • Per trovare dove si trovava HEAD prima di una serie confusa di checkout o merge.

Se il commit è più recente della finestra di scadenza del reflog (90 giorni per le voci raggiungibili per impostazione predefinita), è recuperabile.

Pagine correlate

  • git reset — sposta i ref a una voce del reflog per annullare le modifiche.
  • git rebase — l'operazione di riscrittura che il reflog salva più spesso.
  • git stash — gli stash hanno il proprio reflog sotto stash@{n}.
  • git log — la vista della cronologia normale; git log -g legge il reflog.

Esercitazione

Pratica
Quali sono le affermazioni corrette sul comando `git reflog`?
Quali sono le affermazioni corrette sul comando `git reflog`?
Was this page helpful?