1921

我一直认为你可以通过做来给一个存储命名git stash save stashname,你以后可以通过做来申请git stash apply stashname。但似乎在这种情况下,所发生的一切stashname都将用作存储描述。

有没有办法真正命名一个藏匿处?如果没有,您会推荐什么来实现等效功能?本质上,我有一个小储藏室,我想定期申请,但不想总是寻找git stash list它的实际储藏室编号。

4

27 回答 27

1503

这就是你的做法:

git stash push -m "my_stash"

"my_stash"存储名称在哪里。

一些更有用的事情要知道:所有的存储都存储在一个堆栈中。类型:

git stash list

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

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

git stash pop stash@{n}

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

git stash apply stash@{n}

n隐藏更改的索引在哪里。

请注意,您可以使用存储名称应用存储并将其保存在堆栈中:

git stash apply my_stash_name
于 2013-03-04T08:18:13.163 回答
633

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 手册页

于 2018-03-29T15:08:43.767 回答
187

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

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

# re-apply it later
git apply some.patch

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

于 2017-11-10T16:06:23.897 回答
131

如果你觉得它足够重要,你可以把一个 stash 变成一个分支:

git stash branch <branchname> [<stash>]

从手册页:

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

git stash save如果您运行的分支发生了足够的变化,以至于 git stash apply 由于冲突而失败,这将很有用。由于 stash 应用在 git stash 运行时的 HEAD 提交之上,因此它恢复了最初的隐藏状态,没有冲突。

您可以稍后将这个新分支重新定位到其他地方,该地方是您藏匿时所在位置的后代。

于 2012-06-29T22:34:19.220 回答
59

藏匿处并不意味着像你想要的那样永久存在。在提交时使用标签可能会更好。构建你想要隐藏的东西。做出承诺。为该提交创建一个标签。然后将您的分支回滚到HEAD^. 现在,当您想重新应用该存储时,您可以使用git cherry-pick -n tagname( -nis --no-commit)。

于 2012-06-29T21:39:34.260 回答
55

所以,我不确定为什么这个话题会引起如此多的恐慌。我可以用 a和 deprecated命名 agit stash,并且可以使用正则表达式将其拉回 a :pushsaveapply

git stash 方法使用一个名字来申请

$ git stash push -m "john-hancock"

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

正如之前提到的,该save命令已被弃用,但它仍然有效,因此您可以在无法通过push调用更新它们的旧系统上使用它。与push命令不同,-m开关不需要save.

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

这是 Git 2.2 和 Windows 10。

视觉证明

这是一个漂亮的动画 GIF,演示了这个过程。

动画 GIF 显示 git stash apply 使用可识别的名称。

事件顺序

GIF 运行很快,但如果你看,过程是这样的:

  1. ls命令显示目录中的 4 个文件
  2. touch example.html添加第 5 个文件
  3. git stash push -m "john-hancock" -a-a包括未跟踪的文件)
  4. ls命令在存储后显示 4 个文件,这意味着存储和隐式硬重置有效
  5. git stash apply stash^{/john-hancock}运行
  6. ls命令列出了 5 个文件,显示example.html文件被带回,这意味着该git stash apply命令有效。

这甚至有意义吗?

坦率地说,我不确定这种方法的好处是什么。给存储命名是有价值的,但不是检索。也许编写搁置和取消搁置过程的脚本会有所帮助,但仅按名称弹出一个存储仍然更容易。

$ git stash pop 3
$ git stash apply 3

这对我来说看起来比正则表达式容易得多。

于 2020-06-04T12:24:27.647 回答
53

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

注意:我使用的是git 版本 2.21.0.windows.1

于 2019-09-05T13:40:46.643 回答
49

我的.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
于 2018-06-06T18:53:14.397 回答
36

那这个呢?

git stash save stashname
git stash apply stash^{/stashname}
于 2019-05-07T09:40:23.447 回答
19

用名字保存一个 git stash

$ git stash push -m "say-my-name"

按名称执行 git stash apply

$ git stash apply stash^{/say-my-name}
于 2021-09-23T11:37:22.740 回答
9

Stash 可以使用以下命令自定义注释。

PS D:\git-example> git stash -m "your comment"

列出藏匿处

PS D:\git-exapmle> git stash list

stash@{0}: On master: first stash
stash@{1}: On master: second stash

我们可以选择任何存储,我们必须通过 stash@{x},下面我选择第二个存储,即 1。

PS D:\git-example> git stash pop 1
于 2021-10-04T13:43:36.680 回答
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"
于 2013-11-26T22:51:49.507 回答
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",但我不确定这是否会干扰正则表达式分隔符(我愿意接受建议)。

于 2018-08-09T20:58:57.650 回答
6

别名 对于类 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正则表达式

示例: git sshow MySecretStash

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

于 2014-08-22T17:00:11.577 回答
6

这个答案很大程度上归功于 Klemen Slavič。我本来只是对接受的答案发表评论,但我还没有足够的代表:(

您还可以添加一个 git 别名来查找 stash ref 并在其他别名中使用它来显示、应用、删除等。

[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 以最新的存储为目标,而不是像预期的那样失败。

于 2018-01-11T01:30:02.457 回答
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 是您想要的存储名称的子字符串。

于 2018-02-19T12:56:59.003 回答
4

用来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 别名;)

注意:正如凯文所说,你应该使用标签和樱桃挑选。

于 2017-06-08T15:56:03.283 回答
3

这是我的社区别名:wipwip-apply。当您git wip还存储未跟踪的文件并返回到先前的提交状态时。

git config --global alias.wip '!f() { git stash save $1 -u ; }; f'       

git config --global alias.wip-apply '!f() { temp=$(git stash list | cut -d ':' -f 3 | grep -n -w $1 | cut -d ':' -f 1) ; stashnum=$((temp-1)) ; stashname=$(echo stash@{$stashnum}) ; git stash apply $stashname ; }; f'

用法:

git wip "featureA"
git wip-apply "featureA"
于 2021-12-20T09:05:37.567 回答
2

这里有很多答案,但我相信 OP 所追求的所需等效功能并没有被任何一个答案或评论完全封装。

通过将git addgit diffgit rm和组合git reset到自定义 git 命令中,我们可以快速将更改聚合到补丁文件中,稍后我们可以通过名称轻松引用该文件:

git-bottle-demo

以下是上述自定义 git 命令中使用的命令(也可作为 gist使用) -请注意使用--hard标志将重置您当前的分支以及删除对本地文件的所有更改:

#!/usr/bin/env bash

if [ $# -eq 1 ] ; then
  NAME=$1
else
  echo "Please pass exactly one argument, which is the name of the patch file"
  exit 1
fi

git add .

# if previous patch file with the same name exists untrack it
if [ -f "$NAME.patch" ] ; then
  git rm --cached $NAME.patch
fi

# warning: this will diff all changes into a file called NAME.patch and do a hard reset of the current branch

git diff --staged > $NAME.patch
git reset --hard $HEAD
  • 您现在可以简单git bottle hello地创建一个hello.patch文件。
  • 应用它git apply hello.patch

诀窍是首先跟踪所有文件,以便我们可以利用 diff 命令的暂存(或缓存)选项。通过一些调整,您可以扩展自定义命令以在工作目录之外的某个位置输出补丁文件,即可能在硬盘驱动器上的某个补丁文件夹中,或者您可以更新.gitignore文件以忽略它。

应得的信用:这个答案激发了我自己的灵感,它描述了补丁方法,但忽略了新文件中的更改将被排除在差异显示之外。

警告:由于此命令依赖于它,git add它不会限制 git 已经忽略的任何文件的更改。

于 2021-08-31T12:08:25.400 回答
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''
    }
}

更多细节在这里

于 2017-07-20T19:35:00.780 回答
2

在我的鱼壳里

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

利用

gsap name_of_stash

于 2018-12-26T08:18:02.110 回答
2

git stash apply也适用于除stash@{0}. 所以你可以使用普通的标签来获得一个持久化的名字。这也有一个好处,就是你不会意外git stash dropgit 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
于 2019-01-31T20:53:54.690 回答
1

迟到了,但如果使用 VSCode,一个快速的方法是打开命令面板(CTRL / CMD + SHIFT + P)并输入“Pop Stash”,您将能够按名称检索您的存储无需使用 git CLI

于 2018-11-29T13:45:31.547 回答
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"

我希望它有帮助!

于 2019-12-11T14:54:44.640 回答
0

如果您使用的是 ZSH,则此别名组合非常致命:

zstyle ':completion:*' completer _expand_alias _complete _ignored
alias gs="git stash push -u -m "
alias gsp='git stash pop'

基本上你可以使用 tab 来自动完成你的别名,然后你可以很容易地按名称命名和搜索你的 git stashes。此推送别名还将包括任何未跟踪的文件,我发现默认情况下这些文件很有用。

于 2022-01-13T22:38:19.640 回答
0

对于除了存储创建之外的所有内容,我会通过引入fzf作为依赖项来提出另一种解决方案。我建议您花 5 分钟的时间来了解它,因为它总体上是极大的生产力助推器。

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

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
}
于 2016-09-10T11:58:54.417 回答
-2

这是我做的一个快速设置,对我有用,希望它也对你有用:

假设我的 package.json 项目文件中有一个自定义/本地脚本,我不想推送到远程仓库

{
   // ... package.json stuff
   "scripts": {
       "custom": "ts-node a_ts_test_file.ts"
   }
}

因此,当我想推送我的分支或类似的东西时,我决定存储这个更改,然后弹出存储直到我的下一个“git push”。

所以 ...

  1. 您需要创建一个新的 git 别名:
# dev is the "stash tag"
# To stash current working directory
git config --global alias.sh "stash -m 'dev'"
  1. 您需要编辑您的~.bashrz,或者~.zshrc如果您使用的是 zsh 或 oh-my-zsh,请添加以下别名:
# Apply stash "tagged" $(X) where X is substring of "git stash list" output filtered by output that contains "dev".
# I didn't use git stash apply because "dev" tag isn't unique, so it's a need to pop the stash and ensure to create a new one alias set on first step
alias gitsh="git stash pop $(git stash list | grep 'dev' | cut -d ':' -f 1) || echo 'nope'"
  1. 享受

使用标签“dev”推送您的工作目录:git sh 从标签为“dev”的存储中提取您的隐藏更改:sitsh

(这是我在五分钟内制作的一个小脚本,对我有用,如果它失败了......修复它!)

于 2021-04-14T17:25:23.217 回答