Come estrarre un singolo file (o le modifiche in un file) da un git stash?


776

Vorrei sapere se è possibile estrarre un singolo file o diff di un file da una git stash senza togliere il set di modifiche stash.

Qualcuno potrebbe essere in grado di fornire alcuni suggerimenti / idee su questo?

Risposte:


1132

Nella manpage di git stash puoi leggere (nella sezione "Discussione", subito dopo la descrizione di "Opzioni") che:

Uno stash è rappresentato come un commit il cui albero registra lo stato della directory di lavoro e il suo primo genitore è il commit su HEAD al momento della creazione dello stash.

Quindi puoi trattare lo stash (ad es. stash@{0}È il primo / primo livello) come un commit di unione e usare:

$ git diff stash@{0}^1 stash@{0} -- <filename>

Spiegazione: stash@{0}^1indica il primo genitore della scorta data, che come indicato nella spiegazione sopra è il commit in cui le modifiche sono state riposte. Usiamo questa forma di "git diff" (con due commit) perché stash@{0}/ refs/stashè un commit di tipo merge e dobbiamo dire a git con quale genitore vogliamo differire. Più criptico:

$ git diff stash@{0}^! -- <filename>

dovrebbe anche funzionare (consultare la manpage git rev-parse per la spiegazione della rev^!sintassi, nella sezione "Specifica degli intervalli").

Allo stesso modo, puoi usare git checkout per estrarre un singolo file dallo stash:

$ git checkout stash@{0} -- <filename>

o per salvarlo con un altro nome file:

$ git show stash@{0}:<full filename>  >  <newfile>

o

$ git show stash@{0}:./<relative filename> > <newfile>

(si noti che qui <nome file completo> è il percorso completo di un file relativo alla directory superiore di un progetto (si pensi: rispetto a stash@{0})).


Potrebbe essere necessario proteggere stash@{0}dall'espansione della shell, ovvero usare "stash@{0}"o 'stash@{0}'.


8
Questo è abbastanza bello ... Non ho davvero capito come funzionava la scorta finché non ho letto la tua risposta (che mi ha portato all'aggiunta di git-checkout). In realtà non l'ho capito, quando fai una scorta, git salva DUE commit - uno per lo stato dell'indice e uno per lo stato della copia di lavoro che è una fusione tra l'indice e la HEAD originale. Questo spiega gli strani alberi che ho visto quando visualizzo il repository con "gitk --all" quando sono presenti degli stash.
Pat Notz,

4
Principalmente trovo che l'applicazione di checkout git sia il modo migliore per realizzare ciò che volevo fare. Comunque ero curioso e ricontrollato git checkoutla pagina man. Non è possibile rilasciare il file in un'altra posizione. C'è un riferimento a questo in: stackoverflow.com/questions/888414/…
Danny

84
$ git checkout stash @ {0} - <nomefile> è molto utile, grazie
gravitazione

43
Si noti che l' git checkoutapproccio copia il file esatto dalla scorta - non lo unisce con ciò che sarebbe nella directory di lavoro git stash apply. (Quindi se hai delle modifiche dalla base su cui è stata creata la scorta, andranno persi).
peterflynn,

4
Si noti che per git stash applyunire le modifiche in un file che è stato modificato nella struttura di lavoro da quando il file è stato archiviato, è necessario mettere in scena quel file nella struttura di lavoro. Per far funzionare l'unione automatica, gli stessi file non possono essere modificati sia nella copia di lavoro che nella copia nascosta da unire. Infine, l'applicazione stash non rimuove l'elemento dallo stash come git stash popfarebbe.
Ville,

46

Se lo usi git stash applyinvece di git stash pop, applicherà lo stash al tuo albero di lavoro ma manterrà comunque lo stash.

Fatto ciò, è possibile add/ commitil file desiderato e quindi ripristinare le modifiche rimanenti.


2
Per pop una specifica scorta: git stash pop stash@{0}(elenco delle modifiche stashed: git stash list)
MrYoshiji

Se altri file nella scorta causano un conflitto di unione, git non mi consente di eseguire il commit sul file che desidero :(
cambunctious

33

Esiste un modo semplice per ottenere modifiche da qualsiasi ramo, inclusi gli stash:

$ git checkout --patch stash@{0} path/to/file

È possibile omettere le specifiche del file se si desidera applicare patch in molte parti. O ometti la patch (ma non il percorso) per ottenere tutte le modifiche in un singolo file. Sostituisci 0con il numero di stash da git stash list, se ne hai più di uno. Si noti che questo è simile diffe offre di applicare tutte le differenze tra i rami. Per ottenere le modifiche da un solo commit / stash, dai un'occhiata git cherry-pick --no-commit.


Questo copia il file esatto dallo stash o si unisce? In caso di copia, se si verificano modifiche dalla creazione dello stash, andranno perse.
Danijel,

2
@Danijel Read git help checkout. --patchesegue la fusione interattiva, applica qualunque pezzo approvi nella shell (o qualunque cosa tu salvi se scegli di echiudere la patch). Solo il percorso sovrascriverà il file, come ho scritto, "tutte le modifiche".
Walf

1
leggero miglioramento: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' - quindi facendo git applydiffat stash@{4}usa solo i file che sono cambiati tra la scorta e il suo genitore.
Segna

25

Risposta breve

Per vedere l'intero file: git show stash@{0}:<filename>

Per vedere il diff: git diff stash@{0}^1 stash@{0} -- <filename>


1
Non penso che si preoccupasse di visualizzare lo stash per un determinato file, ma solo di far apparire quel file.
Amalgovinus

1
Questo è quello che stavo cercando. Quindi puoi sostituire diffcon difftoolper usare il tuo diff esterno preferito.
Peet Brits

19
$ git checkout stash@{0} -- <filename>

Appunti:

  1. Assicurati di inserire spazio dopo il "-" e il parametro nome file

  2. Sostituisci zero (0) con il tuo numero di scorta specifico. Per ottenere l'elenco di stash, utilizzare:

    git stash list
    

Basato sulla risposta di Jakub Narębski : versione più breve


11

Puoi ottenere il diff per uno stash con " git show stash@{0}" (o qualunque sia il numero dello stash; vedi "git stash list"). È facile estrarre la sezione del diff per un singolo file.


2
Ancora più semplice per le menti come me: usa git show stashper mostrare la scorta più alta (normalmente l'unica che hai). Allo stesso modo puoi mostrare il diff tra il tuo ramo attuale e lo stash con git diff head stash.
Dizzley,

5

Il concetto più semplice da capire, anche se forse non il migliore, è che hai cambiato tre file e vuoi archiviare un file.

Se lo fai git stashper riporli tutti, git stash applyper riportarli di nuovo e quindi git checkout f.csul file in questione per ripristinarlo efficacemente.

Quando si desidera decomprimere il file in esecuzione, eseguire un git reset --harde quindi eseguire git stash applynuovamente, sfruttando il fatto che git stash applynon cancella il diff dallo stack di stash.


1

Se i file memorizzati devono fondersi con la versione corrente, utilizzare i modi precedenti usando diff. Altrimenti potresti usarlo git popper toglierli di mezzo, git add fileWantToKeepper mettere in scena il tuo file, e fare un git stash save --keep-index, per riporre tutto tranne quello che è sul palco. Ricorda che la differenza in questo modo con i precedenti è che "estrae" il file dalla scorta. Le risposte precedenti lo mantengono git checkout stash@{0} -- <filename>così si adatta alle tue esigenze.


0

Utilizzare quanto segue per applicare le modifiche a un file in uno stash all'albero di lavoro.

git diff stash^! -- <filename> | git apply

Questo è generalmente meglio dell'uso git checkoutperché non perderai le modifiche apportate al file da quando hai creato lo stash.


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.