Come posso recuperare un commit perso in Git?


Risposte:


589

git reflogÈ tuo amico. Trova il commit in cui desideri essere presente in quell'elenco e puoi ripristinarlo (ad esempio:) git reset --hard e870e41.

(Se non hai eseguito il commit delle modifiche ... potresti essere nei guai: commetti in anticipo e commetti spesso!)


5
Dai un'occhiata git log HEAD@{1}. Se sembra la giusta serie di commit, allora puoi farlo git reset HEAD@{1}.
Ambra

4
Solo se i codici sono messi in scena (usando git add), sono mantenuti in git e possono essere trovati facilmente usando comandi come git fsck --lost-found.
Landys,

2
Ho accidentalmente lasciato cadere un impegno che avrei dovuto mantenere durante il rebasing. Questo mi ha totalmente salvato dal rifare un paio di ore di lavoro.
Giuseppe,

27
Questo mi ha salvato la vita.
Lutaaya Huzaifah Idris,

6
Questo mi ha salvato la sanità mentale: D
Frank Fajardo,

120

Prima di rispondere, aggiungiamo alcuni retroscena, spiegando di cosa si HEADtratta.

First of all what is HEAD?

HEADè semplicemente un riferimento al commit corrente (più recente) sul ramo corrente.
Può essercene solo uno HEADin qualsiasi momento (escluso git worktree).

Il contenuto di HEADè memorizzato all'interno .git/HEADe contiene i 40 byte SHA-1 del commit corrente.


detached HEAD

Se non si esegue l'ultimo commit, ovvero HEADviene chiamato un commit precedente nella cronologia detached HEAD.

Inserisci qui la descrizione dell'immagine

Sulla riga di comando, sarà simile al seguente: SHA-1 invece del nome del ramo poiché HEADnon punta alla punta del ramo corrente:

Inserisci qui la descrizione dell'immagine

Inserisci qui la descrizione dell'immagine


Alcune opzioni su come recuperare da una HEAD staccata:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Questo verificherà il nuovo ramo che punta al commit desiderato.
Questo comando eseguirà il checkout per un determinato commit.
A questo punto, puoi creare un ramo e iniziare a lavorare da questo punto in poi.

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Puoi sempre usare refloganche quello.
git reflog visualizzerà qualsiasi modifica che ha aggiornato il HEADe il checkout della voce di reflog desiderata HEADriporterà questo commit.

Ogni volta che HEAD viene modificato, ci sarà una nuova voce in reflog

git reflog
git checkout HEAD@{...}

Questo ti riporterà al commit desiderato

Inserisci qui la descrizione dell'immagine


git reset --hard <commit_id>

"Sposta" HEAD indietro al commit desiderato.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Nota: ( da Git 2.7 ) puoi anche usare git rebase --no-autostashanche questo.

git revert <sha-1>

"Annulla" l'intervallo di commit o commit specificato.
Il comando reset "annulla" tutte le modifiche apportate nel commit dato.
Verrà eseguito il commit di un nuovo commit con la patch di annullamento mentre il commit originale rimarrà anche nella cronologia.

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Questo schema illustra quale comando fa cosa.
Come puoi vedere lì, reset && checkoutmodifica il HEAD.

Inserisci qui la descrizione dell'immagine


2
Sei un eroe, signore
dylanh724,

4
Mi ha risparmiato molte ore di lavoro. Ho usato "git reflog --date = iso" per vedere la data / ora per ogni voce poiché non potrei dirlo senza il timestamp.
MetalMikester,

1
per me, in git reset --hard <commit_id>, rimozione ha HEADfunzionato! +1 per la rappresentazione grafica !!.
reverie_ss,

Solo per citare: se conosci il nome del ramo: git reflog <branchname>può essere molto utile, poiché vedi i cambiamenti di un solo ramo.
Markus Schreiber,

35

Un altro modo per arrivare al commit cancellato è con il git fsckcomando.

git fsck --lost-found

Questo produrrà qualcosa di simile all'ultima riga:

dangling commit xyz

Possiamo verificare che sia lo stesso commit usando reflogcome suggerito in altre risposte. Ora possiamo fare ungit merge

git merge xyz

Nota:
non è possibile recuperare il commit con fsckse abbiamo già eseguito un git gccomando che rimuoverà il riferimento al commit dangling.


3
Questa è l'unica risposta che funziona se non hai recentemente indicato il commit in questione, ad esempio quando recuperi un ramo e poi ripristini accidentalmente quel ramo altrove.
TamaMcGlinn,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.