Annulla git reset –hard con file non salvati nell’area di staging

Sto cercando di recuperare il mio lavoro. Ho stupidamente fatto git reset --hard , ma prima ho fatto solo get add . e non ha fatto git commit . Per favore aiuto! Ecco il mio log:

 MacBookPro:api user$ git status # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # modified: .gitignore ... MacBookPro:api user$ git reset --hard HEAD is now at ff546fa added new strucuture for api 

È ansible annullare git reset --hard in questa situazione?

Dovresti essere in grado di recuperare tutti i file che hai aggiunto all’indice (ad esempio, come nella tua situazione, con git add . ) Anche se potrebbe essere un po ‘di lavoro. Per aggiungere un file all’indice, git lo aggiunge al database degli oggetti, il che significa che può essere ripristinato fino a quando non è ancora avvenuta la garbage collection. C’è un esempio di come fare questo dato nella risposta di Jakub Narębski qui:

  • Ripristino del file aggiunto dopo aver eseguito il ripristino di git –hard HEAD ^

Tuttavia, l’ho provato su un repository di test e ci sono stati un paio di problemi – --cached dovrebbe essere --cache , e ho scoperto che in realtà non creava la directory .git/lost-found . Tuttavia, i seguenti passaggi hanno funzionato per me:

 git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") 

Questo dovrebbe generare tutti gli oggetti nel database degli oggetti che non sono raggiungibili da alcun riferimento, nell’indice o tramite il reflog. L’output sarà simile a questo:

 unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3 unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03 

… e per ognuno di questi BLOB, puoi fare:

 git show 907b308 

Per stampare il contenuto del file.


Troppa produzione?

Aggiornamento in risposta al seguente commento di sehe :

Se si scopre che ci sono molti commit e alberi elencati nell’output da quel comando, è ansible rimuovere dall’output tutti gli oggetti a cui si fa riferimento con commit non referenziati. (In genere si può tornare a questi commit tramite il reflog comunque: ci interessa solo oggetti che sono stati aggiunti all’indice ma che non possono mai essere trovati tramite un commit.)

Innanzitutto, salva l’output del comando, con:

 git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all 

Ora i nomi object di quei commit irraggiungibili possono essere trovati con:

 egrep commit all | cut -d ' ' -f 3 

Quindi puoi trovare solo gli alberi e gli oggetti che sono stati aggiunti all’indice, ma non commessi in alcun punto, con:

 git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \ $(egrep commit all | cut -d ' ' -f 3) 

Questo riduce enormemente il numero di oggetti che devi considerare.


Aggiornamento: Philip Oakley di seguito suggerisce un altro modo di ridurre il numero di oggetti da considerare, che è quello di considerare solo i file modificati più di recente sotto .git/objects . Puoi trovarli con:

 find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort 

(Ho trovato che find invocazione qui .) La fine di tale elenco potrebbe essere simile a:

 2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b 2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a 

Nel qual caso puoi vedere quegli oggetti con:

 git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b git show de629830603289ef159268f443da79968360913a 

(Nota che devi rimuovere / alla fine del percorso per ottenere il nome dell’object).

Ho appena fatto un reset git –hard e ho perso un commit. Ma conoscevo l’hash del commit, quindi sono stato in grado di fare git cherry-pick COMMIT_HASH per ripristinarlo.

L’ho fatto entro pochi minuti dalla perdita del commit, quindi potrebbe funzionare per alcuni di voi.

Grazie a Mark Longair ho recuperato le mie cose!

Per prima cosa ho salvato tutti gli hash in un file:

 git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes 

successivamente li metto tutti (rimuovendo la cosa ‘irraggiungibile blob’) in una lista e metto tutti i dati in nuovi file … devi scegliere i tuoi file e rinominarli di nuovo di cui hai bisogno … ma avevo solo bisogno di alcuni file … questo aiuta qualcuno …

 commits = ["c2520e04839c05505ef17f985a49ffd42809f", "41901be74651829d97f29934f190055ae4e93", "50f078c937f07b508a1a73d3566a822927a57", "51077d43a3ed6333c8a3616412c9b3b0fb6d4", "56e290dc0aaa20e64702357b340d397213cb", "5b731d988cfb24500842ec5df84d3e1950c87", "9c438e09cf759bf84e109a2f0c18520", ... ] from subprocess import call filename = "file" i = 1 for c in commits: f = open(filename + str(i),"wb") call(["git", "show", c],stdout=f) i+=1 

@ La soluzione di Ajedi32 nei commenti ha funzionato per me esattamente in questa situazione.

 git reset --hard @{1} 

Nota che tutte queste soluzioni si basano sul fatto che non c’è git gc, e alcune potrebbero causarne una, quindi riavvolgerei il contenuto della tua directory .git prima di provare qualsiasi cosa in modo che tu abbia un’istantanea a cui tornare se non lo fai lavora per te

Si sono imbattuti nello stesso problema, ma non hanno aggiunto le modifiche all’indice. Quindi tutti i comandi sopra riportati non mi hanno riportato le modifiche desiderate.

Dopo tutte le risposte elaborate sopra, questo è un suggerimento ingenuo, ma potrebbe essere che salverà qualcuno che non ci ha pensato prima, come ho fatto io.

Nella disperazione, ho provato a premere CTRL-Z nel mio editor (LightTable), una volta in ogni scheda aperta – questo per fortuna ha recuperato il file in quella scheda, al suo stato più recente prima del git reset --hard . HTH.

Bontà, mi sono tirato i capelli finché non mi sono imbattuto in questa domanda e nelle sue risposte. Credo che la risposta corretta e concisa alla domanda posta sia disponibile solo se si selezionano due dei commenti sopra riportati, quindi qui è tutto in un unico punto:

  1. Come menzionato da chilicuil, lancia ‘git reflog’ per identificare l’hash di commit in cui vuoi tornare

  2. Come accennato da akimsko, probabilmente NON vuoi eseguire il cherry pick se non hai perso un solo commit, quindi dovresti eseguire ‘git reset –hard

Nota per gli utenti di Eclipse: non sono riuscito a trovare un modo per eseguire questi passaggi all’interno di Eclipse con egit. Chiudere Eclipse, eseguendo i comandi precedenti da una finestra di terminale, e quindi riaprire Eclipse ha funzionato bene per me.

Le soluzioni di cui sopra potrebbero funzionare, tuttavia, ci sono modi più semplici per recuperare da questo, invece di passare attraverso git -s, undo complesso. Direi che la maggior parte dei git-reset si verifica su un numero limitato di file e, se si utilizza già VIM, questa potrebbe essere la soluzione più efficiente in termini di tempo. L’avvertenza è che devi già usare ViM's persistent-undo, che dovresti usare in entrambi i modi, perché ti offre la possibilità di annullare un numero illimitato di modifiche.

Ecco i passaggi:

  1. In vim premere : e digitare il comando set undodir . Se hai triggersto l’ persistent undo nel tuo .vimrc , mostrerà un risultato simile a undodir=~/.vim_runtime/temp_dirs/undodir .

  2. Nel repository utilizzare git log per scoprire l’ultima data / ora in cui è stato effettuato l’ultimo commit

  3. Nella tua shell vai al tuo undodir usando cd ~/.vim_runtime/temp_dirs/undodir .

  4. In questa directory utilizzare questo comando per trovare tutti i file che sono stati modificati dall’ultimo commit

    find . -newermt "2018-03-20 11:24:44" \! -newermt "2018-03-23" \( -type f -regextype posix-extended -regex '.*' \) \-not -path "*/env/*" -not -path "*/.git/*"

    Qui “2018-03-20 11:24:44” è la data e l’ora dell’ultimo commit. Se la data in cui è stato eseguito il git reset --hard è “2018-03-22”, quindi utilizzare “2018-03-22”, quindi utilizzare “2018-03-23”. Ciò è dovuto a una stranezza di trovare, in cui il limite inferiore è inclusivo e il limite superiore è esclusivo. https://unix.stackexchange.com/a/70404/242983

  5. Poi vai su ognuno dei file per aprirli in vim e fai un “precedente 20m”. Puoi trovare maggiori dettagli su “prima” usando “h prima”. Qui in earlier 20m significa tornare allo stato del file 20 minuti indietro, assumendo che hai fatto il git hard --reset , 20 minuti indietro. Ripeti l’operazione su tutti i file estratti dal comando find . Sono sicuro che qualcuno può scrivere una sceneggiatura che combini queste cose.