Domanda

È possibile annullare le modifiche causate dal seguente comando?Se é cosi, come?

git reset --hard HEAD~1
È stato utile?

Soluzione

Pat Notz ha ragione.Puoi recuperare il commit purché sia ​​avvenuto entro pochi giorni.git raccoglie solo i rifiuti dopo circa un mese circa, a meno che tu non gli dica esplicitamente di rimuovere i BLOB più recenti.

$ git init
Initialized empty Git repository in .git/

$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1

$ cat file2
cat: file2: No such file or directory

$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2

$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2

$ cat file2
added new file

Nell'esempio puoi vedere che il file2 è stato rimosso a seguito dell'hard reset, ma è stato rimesso a posto quando ho ripristinato tramite il reflog.

Altri suggerimenti

Quello che vuoi fare è specificare lo sha1 del commit su cui vuoi ripristinare.Puoi ottenere sha1 esaminando il reflog (git reflog) e poi facendo

git reset --hard <sha1 of desired commit>

Ma non aspettare troppo...dopo alcune settimane Git alla fine vedrà il commit come senza riferimenti ed eliminerà tutti i BLOB.

La risposta è nascosta nella risposta dettagliata sopra, puoi semplicemente fare:

$> git reset --hard HEAD@{1}

(Vedi l'output di spettacolo di reflog di git)

È possibile recuperarlo se Git non ha ancora effettuato il garbage collection.

Ottieni una panoramica dei commit pendenti con fsck:

$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Recupera il commit pendente con rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Se sei davvero fortunato, come lo sono stato io, puoi tornare al tuo editor di testo e premere "Annulla".

So che non è proprio una risposta corretta, ma mi ha risparmiato mezza giornata di lavoro, quindi spero che faccia lo stesso per qualcun altro!

Esempio di caso IRL:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
Date:   Wed Aug 15 08:41:30 2012 +0200

    *MY COMMIT MESSAGE IS DISPLAYED HERE*

diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.

per quanto ne so, --hard scarterà le modifiche non salvate.Poiché questi non vengono tracciati da git.ma puoi annullare il discarded commit.

$ git reflog

elencherà:

b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....

Dove 4bac331 è il discarded commit.

Ora sposta la testa su quel commit::

$ git reset --hard 4bac331

Nella maggior parte dei casi sì.

A seconda dello stato in cui si trovava il tuo repository quando hai eseguito il comando, gli effetti di git reset --hard può variare da banale a annullabile, a praticamente impossibile.

Di seguito ho elencato una serie di diversi scenari possibili e il modo in cui potresti riprenderti da essi.

Tutte le mie modifiche sono state confermate, ma ora i commit sono spariti!

Questa situazione di solito si verifica quando corri git reset con una discussione, come in git reset --hard HEAD~.Non preoccuparti, è facile riprendersi!

Se solo scappassi git reset e non hai fatto nient'altro da allora, puoi tornare al punto in cui eri con questa battuta:

git reset --hard @{1}

Ciò ripristina il ramo corrente in qualunque stato si trovasse prima dell'ultima volta che è stato modificato (nel tuo caso, la modifica più recente al ramo sarebbe l'hard reset che stai tentando di annullare).

Se, tuttavia, tu Avere hai apportato altre modifiche al tuo ramo dopo il ripristino, la riga sopra non funzionerà.Invece dovresti correre git reflog <branchname> per visualizzare un elenco di tutte le modifiche recenti apportate al tuo ramo (inclusi i ripristini).L'elenco sarà simile a questo:

7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit

Trova in questo elenco l'operazione che desideri "annullare".Nell'esempio sopra, sarebbe la prima riga, quella che dice "reset:spostandosi su HEAD~".Quindi copia la rappresentazione del commit Prima (sotto) tale operazione.Nel nostro caso, sarebbe così master@{1} (O 3ae5027, entrambi rappresentano lo stesso commit) ed eseguiti git reset --hard <commit> per ripristinare il ramo corrente su quel commit.

Ho messo in scena le mie modifiche con git add, ma mai impegnato.Ora le mie modifiche sono scomparse!

Questo è un po' più complicato da recuperare.idiota fa avere copie dei file che hai aggiunto, ma poiché queste copie non sono mai state legate a nessun commit particolare non puoi ripristinare le modifiche tutte in una volta.Invece, devi individuare i singoli file nel database di Git e ripristinarli manualmente.Puoi farlo usando git fsck.

Per dettagli su questo, vedere Annulla git reset --hard con i file non salvati nell'area di staging.

Ho apportato modifiche ai file nella mia directory di lavoro con cui non ho mai eseguito stage git add, e mai impegnato.Ora le mie modifiche sono scomparse!

Uh Oh.Odio dirtelo, ma probabilmente sei sfortunato.git non memorizza le modifiche che non aggiungi o non impegni e, secondo il documentazione per git reset:

--difficile

Reimposta l'indice e l'albero di lavoro. Eventuali modifiche ai file tracciati nell'albero di lavoro da allora <commit> vengono scartati.

È possibile che tu Potrebbe essere in grado di recuperare le modifiche con una sorta di utilità di ripristino del disco o un servizio di recupero dati professionale, ma a questo punto probabilmente è più un problema che un valore.

Se non hai ancora effettuato la raccolta dei rifiuti nel tuo repository (ad es.utilizzando git repack -d O git gc, ma tieni presente che la garbage collection può anche avvenire automaticamente), il tuo commit sarà ancora lì – semplicemente non sarà più raggiungibile tramite HEAD.

Puoi provare a trovare il tuo commit esaminando l'output di git fsck --lost-found.

Le versioni più recenti di Git hanno qualcosa chiamato "reflog", che è un registro di tutte le modifiche apportate ai riferimenti (al contrario delle modifiche apportate ai contenuti del repository).Quindi, ad esempio, ogni volta che cambi la TESTA (ad es.ogni volta che fai a git checkout per cambiare ramo) che verranno registrati.E, naturalmente, il tuo git reset ha anche manipolato l'HEAD, quindi è stato anche registrato.Puoi accedere agli stati precedenti dei tuoi riferimenti in un modo simile a quello in cui puoi accedere agli stati precedenti del tuo repository, utilizzando un file @ segno invece di a ~, Piace git reset HEAD@{1}.

Mi ci è voluto un po' per capire qual è la differenza tra HEAD@{1} e HEAD~1, quindi ecco una piccola spiegazione:

git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog

COSÌ, HEAD~1 significa "vai al commit prima del commit a cui HEAD punta attualmente", mentre HEAD@{1} significa "vai al commit a cui puntava HEAD prima di puntare a dove punta attualmente".

Ciò ti consentirà facilmente di trovare il tuo commit perduto e recuperarlo.

So che questo è un vecchio thread...ma poiché molte persone sono alla ricerca di modi per annullare alcune cose in Git, penso ancora che potrebbe essere una buona idea continuare a dare suggerimenti qui.

Quando esegui un "git add" o sposti qualcosa dall'alto a sinistra in basso a sinistra in git gui, il contenuto del file viene archiviato in un BLOB ed è possibile ripristinare il contenuto del file da quel BLOB.

Quindi è possibile recuperare un file anche se non è stato depositato ma deve essere stato aggiunto.

git init  
echo hello >> test.txt  
git add test.txt  

Ora il BLOB viene creato ma viene referenziato dall'indice, quindi non verrà elencato con git fsck finché non verrà ripristinato.Quindi resettiamo...

git reset --hard  
git fsck  

otterrai un blob penzolante ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362  

ti restituirà il contenuto del file "ciao".

Per trovare commit senza riferimenti ho trovato un suggerimento da qualche parte che lo suggeriva.

gitk --all $(git log -g --pretty=format:%h)  

L'ho come strumento in Git Gui ed è molto utile.

Prima di rispondere aggiungiamo qualche retroscena, spiegando di cosa si tratta HEAD.

First of all what is HEAD?

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

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


detached HEAD

Se non sei sull'ultimo commit, significa questo HEAD punta a un commit precedente nella cronologia, viene chiamato detached HEAD.

enter image description here

Sulla riga di comando apparirà così: SHA-1 invece del nome del ramo poiché il file HEAD non punta alla punta del ramo corrente

enter image description here


Alcune opzioni su come ripristinare un HEAD staccato:


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 effettuerà il checkout del nuovo ramo che punta al commit desiderato.
Questo comando eseguirà il checkout per un determinato commit.
A questo punto potete creare un ramo e cominciare 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 il reflog anche.
git reflog visualizzerà qualsiasi modifica che ha aggiornato il file HEAD e controllando la voce di reflog desiderata imposterai il file HEAD torniamo a questo impegno.

Ogni volta che si modifica HEAD ci sarà una nuova voce nel file reflog

git reflog
git checkout HEAD@{...}

Questo ti riporterà al commit desiderato

enter image description here


git reset HEAD --hard <commit_id>

"Sposta" la testa 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 il git rebase --no-autostash anche.


git revert <sha-1>

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

# add 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 && checkout modificare il HEAD.

enter image description here

Ho appena eseguito un hard reset sul progetto sbagliato.Ciò che mi ha salvato la vita è stata la storia locale di Eclipse.Si dice che anche IntelliJ Idea ne abbia uno, e anche il tuo editor, vale la pena controllare:

  1. Argomento della guida di Eclipse sulla cronologia locale
  2. http://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F

Ho creato un piccolo script per rendere leggermente più semplice la ricerca del commit che si sta cercando:

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

Sì, può essere reso notevolmente più carino con awk o qualcosa del genere, ma è semplice e ne avevo proprio bisogno.Potrebbe far risparmiare a qualcun altro 30 secondi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top