如何在git中按名称命名和检索存储?


1417

我总是觉得你可以给一个藏匿点一个名字git stash save stashname,以后可以申请给一个名字git stash apply stashname。但是似乎在这种情况下,所有发生的事情都stashname将用作隐藏说明。

没有办法真正命名藏匿处吗?如果没有,您将建议如何实现同等功能?本质上,我有一个很小的存储区,我想定期申请该存储区,但不想一直寻找git stash list其实际存储区号是多少。


68
git stash push -m stashname当前语法git stash save stashname已不推荐使用。
SherylHohman '18

1
git stash push -m stashname在2.8.0.windows.1。中不起作用
杰克(Jac)2018年

Git for Windows 2.26.0于几天前发布。也许现在已修复。github.com/git-for-windows/git/releases/tag/v2.26.0.windows.1
tom_mai78101

Answers:


813

这是您的操作方式:

git stash save "my_stash"

"my_stash"存储名称在哪里。

一些更有用的知识:所有存储区都存储在堆栈中。类型:

git stash list

这将列出您所有的藏匿处。

要应用存储并将其从存储堆栈中删除,请键入:

git stash pop stash@{n}

要应用存储并将其保存在存储堆栈中,请键入:

git stash apply stash@{n}

n隐匿变化的索引在哪里。


88
这不能回答问题。默认情况下,您的存储区会带有一堆数字,但这并不能回答如何输入名称以轻松识别的问题。
2014年

16
OP明确尝试避免使用笨拙的名称stash @ {n}作为自定义名称。git stash apply <custom-name>
stewSquared

10
不回答有关按名称检索存储的问题。
nullsteph

45
git stash push -m my_stash当前语法git stash save my_stash已不推荐使用。
SherylHohman '18

21
这不是无关紧要的。它是有益的。
加安·维拉库蒂

438

git stash save弃用作为2.15.x / 2.16,而不是你可以使用git stash push -m "message"

您可以像这样使用它:

git stash push -m "message"

其中“消息”是您对该存储的注释。

为了检索存储,您可以使用:git stash list。这将输出这样的列表,例如:

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

然后,您只需使用apply以下命令即可stash@{index}

git stash apply stash@{1}

参考 git stash手册页


9
显示push而不是save语法的文档:git stash push
SherylHohman

30
这是真正的答案。不幸的是,上面有很多旧答案。
马兰'18

1
有关更新的更多信息git stash pushstackoverflow.com/a/47231547/6309
VonC

源(在最新的现状DOC)的取消通知:git-scm.com/docs/git-stash/2.24.0#Documentation/...
加布里埃尔Devillers

1
FWIW:git stash apply stash@{1}在Powershell中运行时,您会得到error: unknown switch 'e'回报。而是使用git stash apply --index 1git stash apply 'stash@{1}'或逸出}{加上反引号`。
LosManos

104

如果您觉得它很重要,可以将它变成一个分支:

git stash branch <branchname> [<stash>]

从手册页:

这将创建并签出一个新分支<branchname>,该分支从<stash>最初创建该分支的提交开始,将记录的更改应用于<stash>新的工作树和索引,然后删除<stash>是否成功完成的分支。如果没有<stash>给出,则应用最新的。

如果您运行的分支git stash save已发生足够的更改以至于git stash应用由于冲突而失败,这将非常有用。由于存储是在运行git stash时是HEAD的提交之上应用的,因此它可以恢复原始存储状态,而不会发生冲突。

您以后可以将此新分支重新设置到其他位置,该位置是您存放时的后代。


1
由于分支在git中非常便宜,因此该建议对我最有用。

5
可以,但是如果您以后想继续在其他分支中重新应用此存储(如OP要求的那样),则无济于事。您将不得不挑起它的头。
stewSquared

@AdamDymitruk有什么方法可以执行此操作,同时保持隐藏状态而不会弹出。(例如git stash apply
Kasun Siyambalapitiya '19

奇怪的是,当我尝试这样做时,我收到一条错误消息,指出我的文件之一在签出时将被覆盖,我应该提交或存储(!)我的更改。git stash push -m 'name'工作。
wortwart

@AdamDymmitruk了不起的答案。令我震惊
Dan

75

如果您只是想以一种轻巧的方式保存部分或全部当前的工作副本更改,然后在以后随意重新应用它们,请考虑一个补丁文件:

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

# re-apply it later
git apply some.patch

我时不时地想知道是否应该为此使用藏匿处,然后看到上面的疯狂之类的东西,并且我对正在做的事情感到满意:)


2
就是这个!谢谢。我还更新了.gitignore,以忽略.patch文件,并且我都准备好拥有想要的尽可能多的补丁程序。
LINGS

我可以看到问题背后的意图,那就是每次您从master分支中取出而不提交它们时,都要应用一些本地更改。因此,也许该问题应该已经纠正,并且该答案应该已经被接受为解决方案。也很简单。
进出口银行

46

储物并不是要永久保留您想要的东西。在提交上使用标签可能会更好。构造要隐藏的东西。做出一个承诺。为该提交创建标签。然后将分支回滚到HEAD^。现在,当您想重新应用该存储时,可以使用git cherry-pick -n tagname-nis --no-commit)。


1
绝对像这种方法一样,只是named commit在某个地方闲逛感觉更干净。唯一的烦恼是它不会在选择樱桃时提交,而是停留在差异中,这意味着在下一次提交期间将需要手动不对其进行检入。
Aditya MP 2016年

1
这是最接近的。我想我会为此做一些别名。我不喜欢将描述用作“名称”。
stewSquared

可惜它增加了索引,您必须重新设置,否则有人应该修补一个--no-stage选项!相关:stackoverflow.com/questions/32333383/...
西罗桑蒂利冠状病毒审查六四事件法轮功

41

用于git stash push -m aNameForYourStash保存它。然后使用git stash list来了解要应用的存储区索引。然后使用git stash pop --index 0弹出存储并应用它。

注意:我正在使用git版本2.21.0.windows.1


1
考虑到对当前语法的以下评论,您的答案名义上将是最受好评的答案git stash {push,save}
迈克尔-Where's Clay Shirky

32

我的.zshrc文件中有以下两个功能:

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

以这种方式使用它们:

gitstash nice

gitstashapply nice

什么是“ zsh_stash_name_”?
山姆·哈斯勒

1
@SamHasler只是一些随机的唯一字符串。如果您想知道存储是使用常规git存储或这些功能创建的
iWheelBuy

别名爱好者的
绝佳

21

那这个呢?

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

1
听起来像这样的事情曾经是公认的答案,但已经被删除。
Michael-Clay Shirky在哪里,

嗯,那为什么要删除它?
AdamB

我不知道,因为我没有发布答案,也没有10,000个声誉,但是我想这与说它不起作用的评论有关:很不幸,git stash apply stash^{/<regex>}它不起作用(它不起作用实际搜索存储列表,请查看已接受答案下方的注释)。
Michael-Clay Shirky在哪里,

这就是您要寻找的答案!
kiedysktos

1
对于检索,我进行了1. git stash list向我显示存储区及其关联的索引号,然后进行了2。- git stash apply 0其中0是我从第一条命令中查找的索引号
模棱两可的

8

别名

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

用法

git sapply "<regex>"

  • 与Windows的Git兼容

编辑:我坚持最初的解决方案,但我明白了为什么多数人会喜欢Etan Reisner的版本(如上所述)。因此,仅作记录:

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

使用awk -F: '{print $1}'将完全不需要sed。为什么还要将其包装在函数中呢?并且使用也awk -F: -vpat="$*" '$0 ~ pat {print $1}'应该允许删除grep。虽然可能需要对模式的报价稍有不同。
伊坦·赖斯纳

@EtanReisner:您的代码段输出多行。
VlastimilOvčáčík13年

{print $1; exit}在第一个匹配的行之后退出操作。
Etan Reisner 2013年

@EtanReisner:经过一些测试,我可以摆脱sed,但是包装器和grep仍然存在。
VlastimilOvčáčík13年

您不需要grep,尽管就像我说的那样,没有它,模式引用可能会有所不同。我假设包装程序是指shell函数?您从未解释过为什么您认为自己需要这样做,所以我无法评论您是否确实需要这样做,但我相信您很可能不需要。(您可能需要直接手动调用Shell而不是git stash,但可能甚至不需要。)
Etan Reisner 2013年

8

不幸的是,git stash apply stash^{/<regex>}这行不通(它实际上并没有搜索存储列表,请参见已接受答案中的注释)。

这是git stash list通过正则表达式搜索以找到第一个(最新的)stash@{<n>}然后将其传递给的直接替换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")

请注意,返回了正确的结果代码,因此您可以在其他脚本中使用这些命令。可以使用以下命令运行命令后进行验证:

echo $?

请小心变量扩展漏洞利用,因为我不确定这--grep=$1部分内容。可能应该是,--grep="$1"但是我不确定这是否会影响正则表达式定界符(我愿意接受建议)。


6

这个答案归功于KlemenSlavič。我会在接受的答案上发表评论,但是我没有足够的代表:(

您还可以添加一个git别名来查找存储引用,并将其用于其他别名中以进行显示,应用,放置等。

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

请注意,这种ref=$( ... ); echo ${ref:-<no_match>};模式的原因是不会返回空白字符串,这将导致sshow,sapply和sdrop定位到最新的存储,而不是像预期的那样失败。


1
这对我
有用,而已

4

别名 对于类Unix系统,这可能是更直接的语法,而无需封装在函数中。将以下内容添加到[/ alias]下的〜/ .gitconfig中

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

用法:sapply regex

示例:git sshow MySecretStash

最后的连字符表示从标准输入中获取输入。


4

使用小的bash脚本查找存储的数量。称之为“ gitapply”:

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

用法:

gitapply foo

...其中foo是所需存储区名称的子字符串。


3

采用 git stash save NAME保存。

然后...您可以使用此脚本选择要应用(或弹出)的脚本:

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

我喜欢能够看到隐藏的名称并选择。我也使用Zshell,坦率地说,我不知道如何使用上面的一些Bash别名;)

注意:正如凯文所说,您应该改用标签和樱桃签。


git stash save不推荐使用git stash push
wranvaud

2

这是使用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''
    }
}

在这里更多细节


2

在我的鱼壳里

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

采用

gsap name_of_stash


是! 谢谢!!!
clozach

1

到这里参加聚会很晚,但是如果使用VSCode,一种快速的方法是打开命令面板(CTRL / CMD + SHIFT + P)并键入“ Pop Stash”,您将可以按名称检索您的存储无需使用git CLI


1

git stash apply还可与以外的其他参照一起使用stash@{0}。因此,您可以使用普通标签来获取永久名称。这也具有您不会偶然git stash drop或无法git stash pop

因此,您可以这样定义一个别名pstash(也称为“持久存储”):

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

现在,您可以创建带标签的存储区:

git pstash x-important-stuff

showapply它再次像往常一样:

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

0

我认为没有办法用它的名字git pop stash。

我已经创建了一个执行此操作的bash函数。

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

用法示例:

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

希望对您有所帮助!


0

除了创建隐藏文件外,我还通过引入fzf提出另一种解决方案作为依赖项来。我建议您花费5分钟的时间并开始使用它,因为它总体上可以极大地提高生产力。

无论如何,他们的示例页面中的相关摘录提供了隐藏搜索。更改脚本以添加其他功能(例如隐藏应用程序或删除)非常容易:

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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.