Come nominare e recuperare una scorta per nome in git?


1423

Ho sempre avuto l'impressione che tu potessi dare un nome a una scorta facendo git stash save stashname, cosa che in seguito potresti applicare facendo git stash apply stashname. Ma sembra che in questo caso tutto ciò che accade sia quellostashname verrà usato come descrizione di scorta.

Non c'è modo di nominare effettivamente una scorta? In caso contrario, cosa consiglieresti di ottenere funzionalità equivalenti? Fondamentalmente ho una piccola scorta che vorrei periodicamente applicare, ma non voglio cercare sempre git stash listquale sia il suo numero effettivo di scorta.


68
git stash push -m stashnameè la sintassi corrente . git stash save stashnameè stato deprecato.
SherylHohman,

1
git stash push -m stashname non funziona in 2.8.0.windows.1.
Jac,

Git per Windows 2.26.0 è stato rilasciato pochi giorni fa. Forse ora è stato risolto. github.com/git-for-windows/git/releases/tag/v2.26.0.windows.1
tom_mai78101

Risposte:


818

Ecco come lo fai:

git stash save "my_stash"

Dov'è "my_stash"il nome della scorta.

Alcune cose più utili da sapere: tutti gli stash sono memorizzati in una pila. Genere:

git stash list

Questo elencherà tutte le tue scorte.

Per applicare uno stash e rimuoverlo dallo stack di stash, digitare:

git stash pop stash@{n}

Per applicare uno stash e tenerlo nello stack di stash, digitare:

git stash apply stash@{n}

Dov'è nl'indice della modifica nascosta.


88
Questo non risponde alla domanda. Di default finisci con un mucchio di numeri per la tua scorta, ma questo non risponde a come puoi inserire un nome per identificarlo facilmente.
GoodSp33d

16
OP sta cercando esplicitamente di evitare i nomi stash @ {n} chiamati in modo strano per il nome personalizzato. git stash apply <custom-name>
StewSquared

10
Non risponde alla domanda sul recupero di una scorta per nome.
nullsteph

47
git stash push -m my_stashè la sintassi corrente . git stash save my_stashè stato deprecato.
SherylHohman,

21
Non è irrilevante. È utile.
Gayan Weerakutti,

444

git stash saveè obsoleto a partire da 2.15.x / 2.16, invece puoi usarlogit stash push -m "message"

Puoi usarlo in questo modo:

git stash push -m "message"

dove "messaggio" è la tua nota per quella scorta.

Al fine di recuperare la scorta è possibile utilizzare: git stash list. Questo produrrà un elenco come questo, ad esempio:

stash@{0}: On develop: perf-spike
stash@{1}: On develop: node v10

Quindi usi semplicemente applydandogli il stash@{index}:

git stash apply stash@{1}

Riferimenti alla pagina man di git stash


9
documenti che mostrano pushpiuttosto che savesintassi: git stash push
SherylHohman

30
Questa è la vera risposta. Sfortunatamente, ci sono un sacco di vecchie risposte sopra di esso.
Malan,

1
Per maggiori informazioni sulla più recente git stash push: stackoverflow.com/a/47231547/6309
VonC

fonte (sull'ultimo documento corrente) per l'avviso di deprecazione: git-scm.com/docs/git-stash/2.24.0#Documentation/…
Gabriel Devillers

1
FWIW: Quando git stash apply stash@{1}esegui Powershell otterrai un error: unknown switch 'e'ritorno. Invece usa git stash apply --index 1o git stash apply 'stash@{1}'o scappa }e {con un backtick `.
LosManos,

105

Puoi trasformare uno stash in un ramo se ritieni che sia abbastanza importante:

git stash branch <branchname> [<stash>]

dalla pagina man:

Ciò crea e verifica un nuovo ramo denominato a <branchname>partire dal commit in cui è <stash>stato originariamente creato, applica le modifiche registrate <stash>al nuovo albero di lavoro e al nuovo indice, quindi elimina il <stash>completamento corretto. Quando non <stash>viene fornito, applica l'ultimo.

Ciò è utile se il ramo su cui è stata eseguita git stash saveè cambiato abbastanza da rendere impossibile l'applicazione di git stash a causa di conflitti. Poiché lo stash viene applicato in cima al commit che era HEAD al momento dell'esecuzione di git stash, ripristina lo stato originariamente stash senza conflitti.

In seguito puoi ribasare questo nuovo ramo in un altro posto che discende da dove eri quando sei stato nascosto.


1
Dato che i rami sono piuttosto economici in git, questo suggerimento mi è molto utile.
Jayan,

5
Certo, ma questo non aiuta se si desidera continuare a riapplicare questa scorta in diversi rami in seguito, come sta chiedendo l'OP. Dovresti scegliere la testa della ciliegia.
StewSquared

@AdamDymitruk Esiste un modo per eseguire ciò mantenendo lo stash senza pop. (come in git stash apply)
Kasun Siyambalapitiya l'

Stranamente, quando ho provato questo ho ricevuto un messaggio di errore che uno dei miei file sarebbe stato sovrascritto al momento del check out e avrei dovuto eseguire il commit o lo stash (!) Delle mie modifiche. git stash push -m 'name'lavorato.
Wortwart,

@AdamDymmitruk sorprendente risposta. mi ha fatto impazzire.
Dan,

77

Se stai solo cercando un modo leggero per salvare alcune o tutte le tue attuali modifiche alle copie di lavoro e quindi riapplicarle in seguito a piacimento, considera un file di patch:

# save your working copy changes
git diff > some.patch

# re-apply it later
git apply some.patch

Ogni tanto mi chiedo se dovrei usare stash per questo e poi vedo cose come la follia sopra e sono contento di quello che sto facendo :)


2
Questo è! Grazie. Ho anche aggiornato il mio .gitignore per ignorare i file .patch e sono pronto per avere tutte le patch che voglio.
LINGS

Vedo l'intento alla base della domanda, che è quella di applicare alcune modifiche locali ogni volta che si estrae un ramo dal master e non lo si impegna. Quindi, forse la domanda avrebbe dovuto essere corretta e questa risposta avrebbe dovuto essere accettata come soluzione. Anche semplice.
invia il

46

Gli stash non sono pensati per essere cose permanenti come te. Probabilmente verrai servito meglio usando i tag nelle commit. Costruisci la cosa che vuoi riporre. Impegnati. Crea un tag per quel commit. Quindi ripristinare il ramo a HEAD^. Ora, quando vuoi riapplicare quella scorta, puoi usare git cherry-pick -n tagname( -nè --no-commit).


1
Sicuramente come questo approccio, mi sento un po 'più pulito solo per named commituscire da qualche parte. L'unico fastidio è che non si impegna al momento della scelta della ciliegia e rimane nel diff, il che significa che non dovrà essere registrato manualmente durante il prossimo commit.
Aditya MP il

1
Questo è il più vicino. Penso che farò alcuni alias per questo. Non mi piace usare la descrizione come "nome".
StewSquared

Peccato che aggiunga all'indice e devi resettare, qualcuno dovrebbe patchare --no-stageun'opzione! Correlati: stackoverflow.com/questions/32333383/...
Ciro Santilli郝海东冠状病六四事件法轮功

41

usare git stash push -m aNameForYourStashper salvarlo. Quindi utilizzare git stash listper apprendere l' indice dello stash che si desidera applicare. Quindi utilizzaregit stash pop --index 0 per far apparire lo stash e applicarlo.

nota: sto usando git versione 2.21.0.windows.1


1
La tua risposta è nominalmente quella che sarebbe la risposta più votata, tenendo conto di questo commento sull'attuale sintassi digit stash {push,save}
Michael - Where's Clay Shirky,

32

Ho queste due funzioni nel mio .zshrcfile:

function gitstash() {
    git stash push -m "zsh_stash_name_$1"
}

function gitstashapply() {
    git stash apply $(git stash list | grep "zsh_stash_name_$1" | cut -d: -f1)
}

Usandoli in questo modo:

gitstash nice

gitstashapply nice

Che cos'è "zsh_stash_name_"?
Sam Hasler,

1
@SamHasler solo qualche stringa univoca casuale. Se vuoi sapere che lo stash è stato creato con git stash regolare o con queste funzioni
iWheelBuy

Soluzione elegante per i fan degli alias
suarsenegger il

22

Che dire di questo?

git stash save stashname
git stash apply stash^{/stashname}

1
E suona come una cosa del genere usato per essere la risposta accettata, ma dal momento che è stato eliminato.
Michael - Dov'è Clay Shirky

Hm, allora perché è stato cancellato?
AdamB

Non lo so, dal momento che non ho pubblicato la risposta e non ho una reputazione di 10.000, ma presumo abbia qualcosa a che fare con i commenti dicendo che non funziona: è un peccato che git stash apply stash^{/<regex>}non funzioni (non funziona cerca effettivamente nella lista degli stash, vedi i commenti sotto la risposta accettata ).
Michael - Dov'è Clay Shirky

questa è la risposta che stai cercando!
kiedysktos,

1
per il recupero vado 1. git stash listche mi mostra gli stash insieme al loro numero di indice associato, poi vado 2. git stash apply 0- dove 0 è il numero di indice che avrei cercato dal primo comando
ambidestro

8

Alias

sapply = "!f() { git stash apply \"$(git stash list | awk -F: --posix -vpat=\"$*\" \"$ 0 ~ pat {print $ 1; exit}\")\"; }; f"

uso

git sapply "<regex>"

  • compatibile con Git per Windows

Modifica: mi sono attenuto alla mia soluzione originale, ma vedo perché la maggioranza preferirebbe la versione di Etan Reisner (sopra). Quindi, solo per la cronaca:

sapply = "!f() { git stash apply \"$(git stash list | grep -E \"$*\" | awk \"{ print $ 1; }\" | sed -n \"s/://;1p\")\"; }; f"

L'uso awk -F: '{print $1}'eliminerebbe del tutto la necessità di sed. Inoltre, perché avvolgere questo in una funzione? E l'uso awk -F: -vpat="$*" '$0 ~ pat {print $1}'dovrebbe consentire di far cadere anche il grep. Anche se potrebbe richiedere un preventivo leggermente diverso per il modello.
Etan Reisner,

@EtanReisner: lo snippet genera più di una riga.
Vlastimil Ovčáčík,

Esegui l'azione {print $1; exit}per uscire dopo la prima riga abbinata.
Etan Reisner,

@EtanReisner: dopo alcuni test ho potuto liberarmi della sed, ma wrapper e grep rimangono.
Vlastimil Ovčáčík,

Non hai bisogno del grep anche se, come ho detto, la citazione del modello potrebbe differire senza di essa. Suppongo che per wrapper intendi la funzione shell? Non hai mai spiegato perché pensi di averne bisogno, quindi non posso commentare se lo fai davvero, ma credo che probabilmente non lo farai. (Potrebbe essere necessario invocare manualmente una shell invece di git stash direttamente, ma forse nemmeno quello.)
Etan Reisner,

8

È sfortunato che git stash apply stash^{/<regex>}non funzioni (in realtà non cerca nell'elenco degli stash, vedere i commenti sotto la risposta accettata ).

Qui ci sono sostituzioni drop-in che cercano git stash listper regex per trovare il primo (il più recente) stash@{<n>}e quindi passarlo a git stash <command>:

# standalone (replace <stash_name> with your regex)
(n=$(git stash list --max-count=1 --grep=<stash_name> | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash show "$n" ; else echo "Error: No stash matches" ; return 1 ; fi)
(n=$(git stash list --max-count=1 --grep=<stash_name> | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash apply "$n" ; else echo "Error: No stash matches" ; return 1 ; fi)
# ~/.gitconfig
[alias]
  sshow = "!f() { n=$(git stash list --max-count=1 --grep=$1 | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash show "$n" ; else echo "Error: No stash matches $1" ; return 1 ; fi }; f"
  sapply = "!f() { n=$(git stash list --max-count=1 --grep=$1 | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash apply "$n" ; else echo "Error: No stash matches $1" ; return 1 ; fi }; f"

# usage:

$ git sshow my_stash
 myfile.txt | 1 +
 1 file changed, 1 insertion(+)

$ git sapply my_stash
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   myfile.txt

no changes added to commit (use "git add" and/or "git commit -a")

Si noti che vengono restituiti codici risultato appropriati in modo da poter utilizzare questi comandi all'interno di altri script. Questo può essere verificato dopo aver eseguito i comandi con:

echo $?

Fai solo attenzione agli exploit di espansione variabile perché non ero sicuro della --grep=$1porzione. Forse dovrebbe essere, --grep="$1"ma non sono sicuro che ciò interferirebbe con i delimitatori regex (sono aperto ai suggerimenti).


6

Questa risposta deve molto a Klemen Slavič. Avrei appena commentato la risposta accettata ma non ho ancora abbastanza rappresentante :(

Puoi anche aggiungere un alias git per trovare il ref stash e usarlo in altri alias per mostrare, applicare, rilasciare, ecc.

[alias]
    sgrep = "!f() { ref=$(git --no-pager stash list | grep "$1" | cut -d: -f1 | head -n1); echo ${ref:-<no_match>}; }; f"
    sshow = "!f() { git stash show $(git sgrep "$1") -p; }; f"
    sapply = "!f() { git stash apply $(git sgrep "$1"); }; f"
    sdrop = "!f() { git stash drop $(git sgrep "$1"); }; f"

Si noti che il motivo del motivo ref=$( ... ); echo ${ref:-<no_match>};è che non viene restituita una stringa vuota che causerebbe sshow, sapply e sdrop per indirizzare l'ultima scorta invece di fallire come ci si aspetterebbe.


1
Questo funziona per me mentre la risposta accettata non sembra funzionare (vedi il mio elogio sulla risposta accettata)
Jan Rüegg,

4

Alias Potrebbe trattarsi di una sintassi più diretta per sistemi simili a Unix senza la necessità di incapsularsi in una funzione. Aggiungi quanto segue a ~ / .gitconfig in [alias]

sshow = !sh -c 'git stash show stash^{/$*} -p' -
sapply = !sh -c 'git stash apply stash^{/$*}' -
ssave = !sh -c 'git stash save "${1}"' -

Uso: regex sapply

Esempio: git sshow MySecretStash

Il trattino alla fine dice prendere input da input standard.


4

Usa un piccolo script bash per cercare il numero dello stash. Chiamalo "gitapply":

NAME="$1"
if [[ -z "$NAME" ]]; then echo "usage: gitapply [name]"; exit; fi
git stash apply $(git stash list | grep "$NAME" | cut -d: -f1)

Uso:

gitapply foo

... dove foo è una sottostringa del nome della scorta che desideri.


3

Utilizzare git stash save NAMEper salvare.

Quindi ... puoi usare questo script per scegliere quale applicare (o pop):

#!/usr/bin/env ruby
#git-stash-pick by Dan Rosenstark

# can take a command, default is apply
command = ARGV[0]
command = "apply" if !command
ARGV.clear

stashes = []
stashNames = []
`git stash list`.split("\n").each_with_index { |line, index|
    lineSplit = line.split(": ");
    puts "#{index+1}. #{lineSplit[2]}"
    stashes[index] = lineSplit[0]
    stashNames[index] = lineSplit[2]
}
print "Choose Stash or ENTER to exit: "
input = gets.chomp
if input.to_i.to_s == input
    realIndex = input.to_i - 1
    puts "\n\nDoing #{command} to #{stashNames[realIndex]}\n\n"
    puts `git stash #{command} #{stashes[realIndex]}`
end

Mi piace poter vedere i nomi degli stash e scegliere. Anche io uso Zshell e francamente non sapevo come usare alcuni degli alias Bash sopra;)

Nota: come dice Kevin, dovresti usare invece tag e cherry-picks.


git stash saveè deprecato a favore di git stash push.
Wranvaud,

2

Questo è un modo per ottenere ciò usando PowerShell:

<#
.SYNOPSIS
Restores (applies) a previously saved stash based on full or partial stash name.

.DESCRIPTION
Restores (applies) a previously saved stash based on full or partial stash name and then optionally drops the stash. Can be used regardless of whether "git stash save" was done or just "git stash". If no stash matches a message is given. If multiple stashes match a message is given along with matching stash info.

.PARAMETER message
A full or partial stash message name (see right side output of "git stash list"). Can also be "@stash{N}" where N is 0 based stash index.

.PARAMETER drop
If -drop is specified, the matching stash is dropped after being applied.

.EXAMPLE
Restore-Stash "Readme change"
Apply-Stash MyStashName
Apply-Stash MyStashName -drop
Apply-Stash "stash@{0}"
#>
function Restore-Stash  {
    [CmdletBinding()]
    [Alias("Apply-Stash")]
    PARAM (
        [Parameter(Mandatory=$true)] $message,         
        [switch]$drop
    )

    $stashId = $null

    if ($message -match "stash@{") {
        $stashId = $message
    }

    if (!$stashId) {
        $matches = git stash list | Where-Object { $_ -match $message }

        if (!$matches) {
            Write-Warning "No stashes found with message matching '$message' - check git stash list"
            return
        }

        if ($matches.Count -gt 1) {
            Write-Warning "Found $($matches.Count) matches for '$message'. Refine message or pass 'stash{@N}' to this function or git stash apply"
            return $matches
        }

        $parts = $matches -split ':'
        $stashId = $parts[0]
    }

    git stash apply ''$stashId''

    if ($drop) {
        git stash drop ''$stashId''
    }
}

Maggiori dettagli qui


2

nel mio guscio di pesce

function gsap
  git stash list | grep ": $argv" | tr -dc '0-9' | xargs git stash apply
end

uso

gsap name_of_stash


Sì! Grazie!!!
clozach,

1

In ritardo alla festa qui, ma se si utilizza VSCode, un modo rapido per farlo è aprire la tavolozza dei comandi (CTRL / CMD + MAIUSC + P) e digitare "Pop Stash", si sarà in grado di recuperare lo stash per nome senza la necessità di usare git CLI


1

git stash applyfunziona anche con altri riferimenti che stash@{0}. Quindi puoi usare i normali tag per ottenere un nome persistente. Questo ha anche il vantaggio che non si può accidentalmente git stash dropogit stash pop .

Quindi puoi definire un alias pstash(aka "scorta persistente") come questo:

git config --global alias.pstash '!f(){ git stash && git tag "$1" stash && git stash drop; }; f'

Ora puoi creare una scorta taggata:

git pstash x-important-stuff

ed showe applyancora come al solito:

git stash show x-important-stuff
git stash apply x-important-stuff

0

Non penso che ci sia un modo per far scoppiare una scorta con il suo nome.

Ho creato una funzione bash che lo fa.

#!/bin/bash

function gstashpop {
  IFS="
"
  [ -z "$1" ] && { echo "provide a stash name"; return; }
  index=$(git stash list | grep -e ': '"$1"'$' | cut -f1 -d:)
  [ "" == "$index" ] && { echo "stash name $1 not found"; return; }
  git stash apply "$index"
}

Esempio di utilizzo:

[~/code/site] on master*
$ git stash push -m"here the stash name"
Saved working directory and index state On master: here the stash name

[~/code/site] on master
$ git stash list
stash@{0}: On master: here the stash name

[~/code/site] on master
$ gstashpop "here the stash name"

Spero possa essere d'aiuto!


0

Per tutto, oltre alla creazione di stash, proporrei un'altra soluzione introducendo fzf come dipendenza. Ti consiglio di prenderti 5 minuti del tuo tempo e di farti conoscere, dato che è soprattutto un grande stimolo alla produttività.

Comunque, un estratto correlato dalla loro pagina di esempi che offre la ricerca di oggetti. È molto semplice cambiare lo scriptlet per aggiungere funzionalità aggiuntive (come l'applicazione stash o il rilascio):

fstash() {
    local out q k sha
    while out=$(
            git stash list --pretty="%C(yellow)%h %>(14)%Cgreen%cr %C(blue)%gs" |
            fzf --ansi --no-sort --query="$q" --print-query \
                --expect=ctrl-d,ctrl-b); do
        mapfile -t out <<< "$out"
        q="${out[0]}"
        k="${out[1]}"
        sha="${out[-1]}"
        sha="${sha%% *}"
        [[ -z "$sha" ]] && continue
        if [[ "$k" == 'ctrl-d' ]]; then
            git diff $sha
        elif [[ "$k" == 'ctrl-b' ]]; then
            git stash branch "stash-$sha" $sha
            break;
        else
            git stash show -p $sha
        fi
    done
}

0

Quindi, non sono sicuro del perché ci sia così tanta costernazione su questo argomento. Posso nominare un git stash sia con un push che con il salvataggio deprecato, e posso usare un regex per tirarlo indietro con un applicare:

Git metodo stash per utilizzare un nome da applicare

$ git stash push -m "john-hancock"

$ git stash apply stash^{/john-hancock}

Come è stato menzionato in precedenza, il comando save è obsoleto, ma funziona ancora, quindi è possibile utilizzarlo su sistemi più vecchi in cui non è possibile aggiornarli con una chiamata push. A differenza del comando push, l'opzione -m non è richiesta con il salvataggio.

// save is deprecated but still functional  
$ git stash save john-hancock

Questo è Git 2.2 e Windows 10.

Prova visiva

Ecco una bellissima GIF animata che dimostra il processo.

Le GIF animate che mostrano un git stash si applicano usando un nome identificabile.

Sequenza di eventi

La GIF viene eseguita rapidamente, ma se guardi, il processo è questo:

  1. Il comando ls mostra 4 file nella directory
  2. touch example.html aggiunge un quinto file
  3. git stash push -m "john-hancock" -a (la -a include file non tracciati)
  4. Il comando ls mostra 4 file dopo lo stash, il che significa che lo stash e l'hard reset implicito hanno funzionato
  5. git stash applica stash ^ {/ / john-hancock} viene eseguito
  6. Il comando ls elenca 5 file, mostrando che il file example.html è stato riportato, il che significa che il comando git stash apply ha funzionato.

Ha senso anche questo?

Ad essere sincero, non sono sicuro di quale sia il vantaggio di questo approccio. C'è valore nel dare un nome allo stash, ma non nel recupero. Forse scrivere lo scaffaletto e il processo senza fronzoli sarebbe utile, ma è ancora molto più semplice inserire una scorta per nome.

$ git stash pop 3
$ git stash apply 3

Mi sembra molto più facile della regex.

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.