Domanda

Lo uso spesso git stash E git stash pop per salvare e ripristinare le modifiche nel mio albero di lavoro.Ieri ho apportato alcune modifiche al mio albero di lavoro che avevo nascosto e spuntato, quindi ho apportato ulteriori modifiche al mio albero di lavoro.Mi piacerebbe tornare indietro e rivedere le modifiche nascoste di ieri, ma git stash pop sembra rimuovere tutti i riferimenti al commit associato.

Lo so se lo uso git stash Poi .git/refs/stash contiene il riferimento del commit utilizzato per creare lo stash.E .git/logs/refs/stash contiene tutta la scorta.Ma quei riferimenti se ne vanno git stash pop.So che il commit è ancora nel mio repository da qualche parte, ma non so cosa fosse.

Esiste un modo semplice per recuperare il riferimento al commit stash di ieri?

Tieni presente che questo non è fondamentale per me oggi perché ho backup giornalieri e posso tornare all'albero di lavoro di ieri per ottenere le modifiche.Lo chiedo perché ci deve essere un modo più semplice!

È stato utile?

Soluzione

Una volta che conosci l'hash del commit stash che hai rilasciato, puoi applicarlo come stash:

git stash apply $stash_hash

Oppure puoi creare un ramo separato con

git branch recovered $stash_hash

Successivamente, puoi fare quello che vuoi con tutti i normali strumenti.Quando hai finito, soffia via il ramo.

Trovare l'hashish

Se l'hai appena aperto e il terminale è ancora aperto, lo farai hanno ancora il valore hash stampato da git stash pop sullo schermo (grazie, Dolda).

Altrimenti, puoi trovarlo usando questo per Linux, Unix o Git Bash per Windows:

git fsck --no-reflog | awk '/dangling commit/ {print $3}'

...o utilizzando Powershell per Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

Questo ti mostrerà tutti i commit alle estremità del tuo grafico dei commit a cui non fa più riferimento alcun ramo o tag: ogni commit perso, incluso ogni commit stash che tu abbia mai creato, sarà da qualche parte in quel grafico.

Il modo più semplice per trovare lo stash commit che desideri è probabilmente passare quell'elenco gitk:

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

...o vedere la risposta di emragins se si utilizza Powershell per Windows.

Questo avvierà un browser del repository che ti mostrerà ogni singolo commit nel repository di sempre, indipendentemente dal fatto che sia raggiungibile o meno.

Puoi sostituire gitk lì con qualcosa del genere git log --graph --oneline --decorate se preferisci un bel grafico sulla console rispetto a un'app GUI separata.

Per individuare i commit stash, cerca i messaggi di commit di questo modulo:

WIP attivato qualche ramo: commithash Qualche vecchio messaggio di commit

Nota:Il messaggio di commit sarà in questo formato (iniziando con "WIP attivo") solo se non hai fornito un messaggio quando lo hai fatto git stash.

Altri suggerimenti

Se non hai chiuso il terminale, guarda l'output di git stash pop e avrai l'ID oggetto della scorta caduta.Normalmente appare così:

$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

(Notare che git stash drop produce anche la stessa riga.)

Per recuperare quella scorta, corri git branch tmp 2cae03e, e lo otterrai come ramo.Per convertirlo in una scorta, esegui:

git stash apply tmp
git stash

Averlo come ramo permette anche di manipolarlo liberamente;ad esempio, per selezionarlo o unirlo.

Volevo solo menzionare questa aggiunta alla soluzione accettata.Non mi è stato subito chiaro la prima volta che ho provato questo metodo (forse avrebbe dovuto esserlo), ma per applicare lo stash dal valore hash, basta usare "git stash apply":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

Quando ero nuovo a Git, questo non mi era chiaro e stavo provando diverse combinazioni di "git show", "git apply", "patch", ecc.

Per ottenere l'elenco delle scorte che sono ancora nel tuo repository, ma non più raggiungibili:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

Se hai dato un titolo alla tua scorta, sostituisci "WIP" in -grep=WIP alla fine del comando con una parte del tuo messaggio, ad es. -grep=Tesselation.

Il comando sta cercando "WIP" perché il messaggio di commit predefinito per uno stash è nel modulo WIP on mybranch: [previous-commit-hash] Message of the previous commit.

Ho appena creato un comando che mi ha aiutato a trovare il mio commit stash perduto:

for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less

Questo elenca tutti gli oggetti nell'albero .git/objects, individua quelli di tipo commit, quindi mostra un riepilogo di ciascuno.Da questo punto è stata solo questione di esaminare i commit per trovare un "WIP on work" appropriato:6a9bb2" ("lavoro" è il mio ramo, 619bb2 è un commit recente).

Noto che se utilizzo "git stash apply" invece di "git stash pop" non avrei questo problema, e se utilizzo "git stash save Messaggio" allora il commit potrebbe essere stato più facile da trovare.

Aggiornamento:Con l'idea di Nathan, questo diventa più breve:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less

git fsck --unreachable | grep commit dovrebbe mostrare sha1, anche se l'elenco restituito potrebbe essere piuttosto lungo. git show <sha1> mostrerà se è il commit che desideri.

git cherry-pick -m 1 <sha1> unirà il commit nel ramo corrente.

Se vuoi ripristinare una scorta perduta, devi prima trovare l'hash della scorta perduta.

Come suggeriva Aristotele Pagaltzis a git fsck dovrebbe aiutarti.

Personalmente utilizzo il mio log-all alias che mi mostra ogni commit (commit recuperabili) per avere una visione migliore della situazione:

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

Puoi effettuare una ricerca ancora più veloce se stai cercando solo i messaggi "WIP attivo".

Una volta che conosci il tuo sha1, cambi semplicemente il reflog della tua scorta per aggiungere la vecchia scorta:

git update-ref refs/stash ed6721d

Probabilmente preferirai avere un messaggio associato, quindi a -m

git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

E vorrai anche usarlo come alias:

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1

Equivalente a Windows PowerShell utilizzando gitk:

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

Probabilmente esiste un modo più efficiente per farlo in un unico tubo, ma questo fa il lavoro.

Mi è piaciuto l'approccio di Aristotele, ma non mi è piaciuto usare GITK...poiché sono abituato a usare GIT dalla riga di comando.

Invece, ho preso i commit penzolanti e ho generato il codice in un file DIFF per la revisione nel mio editor di codice.

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

Ora puoi caricare il file diff/txt risultante (si trova nella tua cartella home) nel tuo editor txt e vedere il codice effettivo e lo SHA risultante.

Quindi basta usare

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

In OSX con git v2.6.4, ho appena eseguito git stash drop accidentalmente, poi l'ho trovato seguendo i passaggi seguenti

Se conosci il nome della scorta, usa:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>

altrimenti troverai l'ID dal risultato manualmente con:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

Quindi, quando trovi l'id commit, premi semplicemente git stash applica {commit-id}

Spero che questo aiuti qualcuno rapidamente

Perché le persone fanno questa domanda?Perché ancora non conoscono né capiscono il reflog.

La maggior parte delle risposte a questa domanda forniscono comandi lunghi con opzioni che quasi nessuno ricorderà.Quindi le persone entrano in questa domanda e copiano e incollano tutto ciò di cui pensano di aver bisogno e lo dimenticano quasi immediatamente dopo.

Consiglierei a tutti coloro che hanno questa domanda di controllare semplicemente il reflog (git reflog), non molto di più.Una volta visualizzato l'elenco di tutti i commit, ci sono cento modi per scoprire quale commit stai cercando e selezionarlo o creare un ramo da esso.Nel processo avrai imparato a conoscere il reflog e le opzioni utili per vari comandi git di base.

Puoi elencare tutti i commit irraggiungibili scrivendo questo comando nel terminale -

git fsck --unreachable

Controlla l'hash di commit irraggiungibile -

git show hash

Infine fai domanda se trovi l'oggetto nascosto -

git stash apply hash

Voglio aggiungere alla soluzione accettata un altro buon modo per eseguire tutte le modifiche, quando non hai gitk disponibile o non hai X per l'output.

git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits

for h in `cat tmp_commits`; do git show $h | less; done

Quindi ottieni tutte le differenze per quegli hash visualizzati uno dopo l'altro.Premi 'q' per passare alla differenza successiva.

La risposta accettata da Aristotele mostrerà tutti i commit raggiungibili, inclusi i commit non simili a stash.Per filtrare il rumore:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3

Ciò includerà solo i commit che hanno esattamente 3 commit principali (che avrà uno stash) e il cui messaggio include "WIP on".

Tieni presente che se hai salvato la tua scorta con un messaggio (ad es. git stash save "My newly created stash"), questo sovrascriverà il messaggio predefinito "WIP su...".

Puoi visualizzare più informazioni su ciascun commit, ad es.visualizzare il messaggio di commit o passarlo a git stash show:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3 | \
xargs -n1 -I '{}' bash -c "\
  git log -1 --format=medium --color=always '{}'; echo; \
  git stash show --color=always '{}'; echo; echo" | \
less -R

Non sono riuscito a far funzionare nessuna delle risposte su Windows in una semplice finestra di comando (Windows 7 nel mio caso). awk, grep E Select-string non sono stati riconosciuti come comandi.Quindi ho provato un approccio diverso:

  • prima corsa: git fsck --unreachable | findstr "commit"
  • copiare l'output nel blocco note
  • find sostituisci "commit irraggiungibile" con start cmd /k git show

sarà simile a questo:

start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4 start cmd /k git show 44078733e1b36962571019126243782421fcd8ae start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1 start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e

  • salva come file .bat ed eseguilo
  • lo script aprirà una serie di finestre di comando, mostrando ogni commit
  • se hai trovato quello che stai cercando, esegui: git stash apply (your hash)

potrebbe non essere la soluzione migliore, ma ha funzionato per me

Quello che sono venuto qui a cercare è come recuperare effettivamente la scorta, indipendentemente da ciò che ho controllato.In particolare, avevo nascosto qualcosa, poi ho controllato una versione precedente, quindi l'ho aperta, ma la scorta non era operativa in quel momento precedente, quindi la scorta è scomparsa;Non potevo semplicemente farlo git stash per rimetterlo in pila.Questo ha funzionato per me:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

In retrospettiva, avrei dovuto usarlo git stash apply non git stash pop.Stavo facendo un bisect e avevo una piccola patch che volevo applicare ad ogni bisect fare un passo.Ora sto facendo questo:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.

Recuperato utilizzando i seguenti passaggi:

  1. Identificare il codice hash stash eliminato:

    gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

  2. Cherry Pick the Stash:

    git cherry-pick -m 1 $stash_hash_code

  3. Risolvi eventuali conflitti utilizzando:

    git mergetool

Inoltre potresti riscontrare problemi con il messaggio di commit se stai utilizzando gerrit.Metti da parte le modifiche prima di seguire le alternative successive:

  1. Utilizzare l'hard reset al commit precedente e quindi eseguire nuovamente il commit di questa modifica.
  2. Puoi anche nascondere la modifica, effettuare il rebase e il reimpegno.

Ho rimosso accidentalmente la scorta nell'app GitUP.Basta premere Ctrl+Z per annullarlo.

Magari aiuta qualcuno ;)

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