Jak nazwać i odzyskać skrytkę według nazwy w git?

1417

Zawsze miałem wrażenie, że możesz nadać skrytce nazwę, robiąc to git stash save stashname, co później możesz złożyć git stash apply stashname. Ale wydaje się, że w tym przypadku wszystko, co się stanie, stashnamezostanie użyte jako opis skrytki.

Czy nie ma sposobu na nazwanie skrytki? Jeśli nie, to co byś polecił, aby osiągnąć równoważną funkcjonalność? Zasadniczo mam małą skrytkę, którą chciałbym okresowo stosować, ale nie chcę zawsze musieć polować, git stash listjaka jest jej rzeczywista liczba.

Suan
źródło
68
git stash push -m stashnamejest bieżącą składnią . git stash save stashnamezostał wycofany.
SherylHohman,
1
git stash push -m nazwa-skrytki nie działa w 2.8.0.windows.1.
Jac
Git dla Windows 2.26.0 został wydany kilka dni temu. Może jest to teraz naprawione. github.com/git-for-windows/git/releases/tag/v2.26.0.windows.1
tom_mai78101

Odpowiedzi:

815

Tak to się robi:

git stash save "my_stash"

Gdzie "my_stash"jest nazwa skrytki.

Kilka bardziej przydatnych rzeczy, które warto wiedzieć: Wszystkie skrytki są przechowywane w stosie. Rodzaj:

git stash list

Spowoduje to wyświetlenie wszystkich twoich skrytek.

Aby zastosować skrytkę i usunąć ją ze stosu skrytki, wpisz:

git stash pop stash@{n}

Aby zastosować skrytkę i zachować ją w stosie, wpisz:

git stash apply stash@{n}

Gdzie njest indeks ukrytej zmiany.

Sri Murthy Upadhyayula
źródło
88
To nie odpowiada na pytanie. Domyślnie twoja skrytka zawiera wiele liczb, ale nie odpowiada to, w jaki sposób możesz łatwo podać nazwę.
GoodSp33d,
16
OP jednoznacznie próbuje uniknąć niezgrabnie nazwanych nazw skrytek @ {n} dla niestandardowej nazwy. git stash apply <custom-name>
gulasz Kwadrat
10
Nie odpowiada na pytanie dotyczące wyszukiwania skrytki według nazwy.
nullsteph
45
git stash push -m my_stashjest bieżącą składnią . git stash save my_stashzostał wycofany.
SherylHohman,
21
To nie jest bez znaczenia. To jest użyteczne.
Gayan Weerakutti
440

git stash savejest przestarzałe od 2.15.x / 2.16, zamiast tego możesz użyćgit stash push -m "message"

Możesz użyć tego w następujący sposób:

git stash push -m "message"

gdzie „wiadomość” jest notatką dla tego skrytki.

W celu odzyskania zapas można użyć: git stash list. Spowoduje to wyświetlenie takiej listy, na przykład:

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

Następnie wystarczy applypodać stash@{index}:

git stash apply stash@{1}

Odnośniki Strona podręcznika git stash

EssaidiM
źródło
9
dokumenty pokazujące pushzamiast saveskładni: git stash push
SherylHohman,
30
To jest prawdziwa odpowiedź. Niestety, nad nią jest mnóstwo starych odpowiedzi.
malan
1
Więcej informacji na temat nowszego git stash push: stackoverflow.com/a/47231547/6309
VonC
źródło (w najnowszym aktualnym dokumencie) powiadomienia o wycofaniu: git-scm.com/docs/git-stash/2.24.0#Documentation/...
Gabriel Devillers,
1
FWIW: Gdy uruchomisz git stash apply stash@{1}Powershell, otrzymasz error: unknown switch 'e'zwrot. Zamiast tego użyj git stash apply --index 1lub git stash apply 'stash@{1}'lub ucieczki }i {za pomocą backticka `.
LosManos
104

Możesz zmienić skrytkę w gałąź, jeśli uważasz, że jest to wystarczająco ważne:

git stash branch <branchname> [<stash>]

ze strony podręcznika:

Spowoduje to utworzenie i sprawdzenie nowej gałęzi o nazwie <branchname>zaczynającej się od zatwierdzenia, w którym <stash>został pierwotnie utworzony, zastosowanie zmian zarejestrowanych w <stash>nowym drzewie roboczym i indeksie, a następnie upuszczenie<stash> jeśli zakończy się pomyślnie. Gdy nie <stash>podano, stosuje się najnowszą.

Jest to przydatne, jeśli gałąź, na której działałeś git stash save , zmieniła się na tyle, że zastosowanie git stash nie powiedzie się z powodu konfliktów. Ponieważ skrytka jest nakładana na zatwierdzenie, które było HEAD w czasie uruchamiania skrytki git, przywraca pierwotnie ukryty stan bez żadnych konfliktów.

Później możesz zmienić bazę tej nowej gałęzi w inne miejsce, które jest potomkiem miejsca, w którym byłeś, kiedy się ukryłeś.

Adam Dymitruk
źródło
1
Ponieważ gałęzie są dość tanie w git, ta sugestia jest dla mnie najbardziej przydatna.
Jayan
5
Jasne, ale to nie pomaga, jeśli chcesz nadal stosować tę skrytkę później w różnych gałęziach, tak jak prosi OP. Musiałbyś poderwać głowę.
gulasz Kwadrat
@AdamDymitruk Czy jest jakiś sposób, aby to zrobić, zachowując zapas bez wyskakiwania. (jak w git stash apply)
Kasun Siyambalapitiya
O dziwo, gdy próbowałem, dostałem komunikat o błędzie, że jeden z moich plików zostanie zastąpiony podczas sprawdzania i powinienem zatwierdzić lub ukryć (!) Moje zmiany. git stash push -m 'name'pracował
wortwart
@AdamDymmitruk niesamowita odpowiedź. oszołomiło mnie.
Dan
75

Jeśli szukasz lekkiego sposobu na zapisanie niektórych lub wszystkich bieżących zmian kopii roboczej, a następnie ich późniejsze zastosowanie, rozważ plik łatki:

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

# re-apply it later
git apply some.patch

Co jakiś czas zastanawiam się, czy powinienem do tego używać skrytek, a potem widzę takie rzeczy jak szaleństwo powyżej i jestem zadowolony z tego, co robię :)

Pat Niemeyer
źródło
2
To jest to! Dziękuję Ci. Zaktualizowałem również mój .gitignore, aby ignorować pliki .patch i jestem gotowy, aby mieć tyle łatek, ile chcę.
LINGS
Widzę cel, jaki kryje się za tym pytaniem, jakim jest wprowadzanie lokalnych zmian za każdym razem, gdy wyjmiesz oddział z mastera i nie zatwierdzisz ich. Być może więc pytanie powinno zostać poprawione, a ta odpowiedź powinna zostać zaakceptowana jako rozwiązanie. Również proste.
ank
46

Skrytki nie mają być trwałymi rzeczami, jak chcesz. Prawdopodobnie lepiej byłoby Ci użyć tagów na zatwierdzeniach. Zbuduj coś, co chcesz schować. Dokonaj zatwierdzenia z tego. Utwórz tag dla tego zatwierdzenia. Następnie wycofaj swój oddział do HEAD^. Teraz, gdy chcesz ponownie zastosować tę skrytkę, możesz użyć git cherry-pick -n tagname( -njest --no-commit).

Lily Ballard
źródło
1
Zdecydowanie tak jak to podejście, wydaje się nieco czystsze po prostu named commitgdzieś spędzać wolny czas. Jedyną łagodną irytacją jest to, że nie zostaje popełnione przy wyborze cherry i pozostaje w diff, co oznacza, że ​​nie będzie trzeba go ręcznie sprawdzać podczas następnego zatwierdzania.
Aditya MP
1
To jest najbliższe. Myślę, że zrobię dla tego kilka aliasów. Nie lubię używać opisu jako „imienia”.
gulasz Kwadrat
Szkoda, że ​​to dodaje do indeksu i musisz zresetować, ktoś powinien załatać --no-stageopcję! Powiązane: stackoverflow.com/questions/32333383/...
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功
41

użyj, git stash push -m aNameForYourStashaby go zapisać. Następnie użyj, git stash listaby poznać indeks skrytki , którą chcesz zastosować. Następnie użyj, git stash pop --index 0aby otworzyć zapas i zastosować go.

Uwaga: używam gita w wersji 2.21.0.windows.1

Canbax
źródło
1
Twoja odpowiedź jest nominalnie tym, która byłaby najwyżej oceniana, biorąc pod uwagę ten komentarz dotyczący obecnej składnigit stash {push,save}
Michael - Where's Clay Shirky
32

Mam dwie funkcje w moim .zshrcpliku:

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)
}

Używając ich w ten sposób:

gitstash nice

gitstashapply nice
iWheelBuy
źródło
Co to jest „zsh_stash_name_”?
Sam Hasler,
1
@SamHasler tylko kilka losowych unikalnych ciągów. Jeśli chcesz wiedzieć, że skrytka została utworzona przy użyciu zwykłej skrytki git lub tych funkcji
iWheelBuy
Eleganckie rozwiązanie dla fanów aliasów
suarsenegger
22

A co z tym?

git stash save stashname
git stash apply stash^{/stashname}
AdamB
źródło
1
To brzmi jak coś takiego kiedyś przyjętym odpowiedź, ale został już usunięty.
Michael - Where's Clay Shirky
Hm, to dlaczego został usunięty?
AdamB
Nie wiem, ponieważ nie opublikowałem odpowiedzi i nie mam 10 000 reputacji, ale zakładam, że ma to coś wspólnego z komentarzami mówiącymi, że nie działa: To niefortunne, że git stash apply stash^{/<regex>}nie działa (nie działa faktycznie przeszukaj listę skrytek, zobacz komentarze pod zaakceptowaną odpowiedzią ).
Michael - Where's Clay Shirky
to jest odpowiedź, której szukasz!
kiedysktos
1
do pobierania Idę 1., git stash listktóra pokazuje mi skrytki wraz z powiązanym z nimi numerem indeksu, a następnie Idę 2. git stash apply 0- gdzie 0 to numer indeksu, którego szukałbym od pierwszego polecenia
oburęczny
8

Alias

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

Stosowanie

git sapply "<regex>"

  • kompatybilny z Git dla Windows

Edycja: Trzymałem się mojego oryginalnego rozwiązania, ale rozumiem, dlaczego większość wolałaby wersję Etana Reisnera (powyżej). Tak dla przypomnienia:

sapply = "!f() { git stash apply \"$(git stash list | grep -E \"$*\" | awk \"{ print $ 1; }\" | sed -n \"s/://;1p\")\"; }; f"
Vlastimil Ovčáčík
źródło
Korzystanie awk -F: '{print $1}'całkowicie wyeliminuje potrzebę sed. Także po co zawijać to w funkcję? Używanie awk -F: -vpat="$*" '$0 ~ pat {print $1}'powinno również pozwolić na upuszczenie grep. Chociaż może wymagać nieco innego cytowania wzoru.
Etan Reisner
@EtanReisner: Twój fragment wyświetla więcej niż jedną linię.
Vlastimil Ovčáčík
Wykonaj akcję, {print $1; exit}aby zakończyć po pierwszej dopasowanej linii.
Etan Reisner
@EtanReisner: Po kilku testach mogłem pozbyć się sed, ale opakowanie i grep pozostają.
Vlastimil Ovčáčík
Nie potrzebujesz grepa, ale jak powiedziałem, cytowanie wzoru może się bez niego różnić. Zakładam, że przez wrapper masz na myśli funkcję powłoki? Nigdy nie wyjaśniłeś, dlaczego uważasz, że jest to potrzebne, więc nie mogę komentować, czy rzeczywiście tak robisz, ale sądzę, że prawdopodobnie nie. (Może być konieczne ręczne wywołanie powłoki zamiast git stash bezpośrednio, ale być może nawet nie to.)
Etan Reisner,
8

To niefortunne, że git stash apply stash^{/<regex>}nie działa (tak naprawdę nie przeszukuje listy skrytek, zobacz komentarze pod zaakceptowaną odpowiedzią ).

Oto zamienniki drop-in, które wyszukują git stash listwedług wyrażenia regularnego, aby znaleźć pierwszą (najnowszą), stash@{<n>}a następnie przekazać ją do 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")

Zwróć uwagę, że zwracane są odpowiednie kody wynikowe, dzięki czemu możesz używać tych poleceń w innych skryptach. Można to zweryfikować po uruchomieniu poleceń za pomocą:

echo $?

Uważaj tylko na exploity zmiennej ekspansji, ponieważ nie byłem pewien tej --grep=$1części. Powinno tak być, --grep="$1"ale nie jestem pewien, czy to przeszkadzałoby w ogranicznikach wyrażeń regularnych (jestem otwarty na sugestie).

Zack Morris
źródło
6

Ta odpowiedź wiele zawdzięcza Klemenowi Slavičowi. Chciałbym właśnie skomentować zaakceptowaną odpowiedź, ale nie mam jeszcze wystarczającej liczby przedstawicieli :(

Możesz także dodać alias git, aby znaleźć odnośnik do skrytki i użyć go w innych aliasach do pokazu, zastosowania, upuszczenia itp.

[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"

Zauważ, że powodem tego ref=$( ... ); echo ${ref:-<no_match>};wzorca jest to, że pusty łańcuch nie jest zwracany, co spowodowałoby, że sshow, sapply i sdrop celowały w najnowszą skrytkę zamiast zawieść, jak można by oczekiwać.

Natanael
źródło
1
Działa to dla mnie, gdy zaakceptowana odpowiedź nie wydaje się działać (zobacz mój komentarz na temat zaakceptowanej odpowiedzi)
Jan Rüegg
4

Alias Może to być bardziej bezpośrednia składnia dla systemów uniksopodobnych bez konieczności enkapsulacji w funkcji. Dodaj następujące elementy do ~ / .gitconfig w [alias]

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

Zastosowanie: sapply regex

Przykład: git sshow MySecretStash

Myślnik na końcu mówi, że pobiera dane ze standardowego wejścia.

Rohanthewiz
źródło
4

Użyj małego skryptu bash, aby sprawdzić numer skrytki. Nazwij to „gitapply”:

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

Stosowanie:

gitapply foo

... gdzie foo jest podciągiem nazwy skrytki, którą chcesz.

Will Sheppard
źródło
3

Posługiwać się git stash save NAME aby zapisać.

Następnie ... możesz użyć tego skryptu, aby wybrać, który chcesz zastosować (lub 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

Lubię widzieć nazwy skrytek i wybierać. Używam również Zshell i szczerze mówiąc nie wiedziałem, jak używać niektórych z powyższych aliasów Bash;)

Uwaga: Jak mówi Kevin, powinieneś zamiast tego używać tagów i cherry-picks.

Dan Rosenstark
źródło
git stash savejest przestarzałe na korzyść git stash push.
wranvaud,
2

Jest to jeden ze sposobów osiągnięcia tego za pomocą 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''
    }
}

Więcej informacji tutaj

Geoffrey Hudik
źródło
2

w mojej skorupce rybnej

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

posługiwać się

gsap name_of_stash

Matsumoto Kazuya
źródło
Tak! Dziękuję Ci!!!
clozach
1

Późno na imprezę tutaj, ale jeśli używasz VSCode, szybkim sposobem na to jest otwarcie palety poleceń (CTRL / CMD + SHIFT + P) i wpisanie „Pop Stash”, będziesz mógł odzyskać swoją skrytkę według nazwy bez potrzeby używania git CLI

Alexandre Gomes
źródło
1

git stash applydziała również z innymi numerami niż stash@{0}. Możesz więc użyć zwykłych tagów, aby uzyskać trwałą nazwę. Ma to również tę zaletę, że nie można przypadkowo git stash droplub git stash popinaczej.

Możesz więc zdefiniować alias pstash(zwany „trwałym ukrytym”) w następujący sposób:

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

Teraz możesz utworzyć oznaczoną skrytkę:

git pstash x-important-stuff

a showi applyto znowu jak zwykle:

git stash show x-important-stuff
git stash apply x-important-stuff
AH
źródło
0

Nie sądzę, że istnieje sposób, aby pop skasować skrytkę po nazwie.

Stworzyłem funkcję bash, która to robi.

#!/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"
}

Przykład użycia:

[~/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"

Mam nadzieję, że to pomoże!

franzisk
źródło
0

Dla wszystkiego oprócz tworzenia skrytki zaproponowałbym inne rozwiązanie, wprowadzając fzf jako zależność. Polecam poświęcić 5 minut i zaznajomić się z tym, ponieważ jest to ponadprzeciętne zwiększenie wydajności.

W każdym razie pokrewny fragment ich strony z przykładami oferuje wyszukiwanie skrytek. Bardzo łatwo jest zmienić skryptlet, aby dodać dodatkowe funkcje (takie jak ukrywanie aplikacji lub upuszczanie):

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
}
Laur
źródło