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

时间:2012-06-29 21:33:21

标签: git git-stash

我总是认为你可以通过git stash save stashname来保存一个名字,以后可以通过git stash apply stashname申请。但似乎在这种情况下,所有发生的事情都是stashname将被用作藏匿描述。

有没有办法真正命名藏匿?如果没有,你会建议什么实现相同的功能?基本上我有一个小的藏匿,我会定期申请,但不想总是在git stash list中寻找它的实际藏匿号码。

22 个答案:

答案 0 :(得分:504)

您就是这样做的:

git stash save "my_stash"

其中"my_stash"是藏匿名称。

要了解更多有用的信息:所有存储都存储在堆栈中。 类型:

git stash list

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

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

git stash pop stash@{n}

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

git stash apply stash@{n}

n是隐藏更改的索引。

答案 1 :(得分:171)

自2.15.x / 2.16起

git stash save 已弃用,您可以使用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 man page

答案 2 :(得分:81)

如果你认为它足够重要,你可以把藏匿处变成一个分支:

git stash branch <branchname> [<stash>]

来自手册页:

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

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

你可以稍后将这个新分支重新绑定到其他地方,这个地方是你藏匿时所处的位置。

答案 3 :(得分:38)

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

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

# re-apply it later
git apply some.patch

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

答案 4 :(得分:38)

Stashes并不是你想要的永久性东西。在提交时使用标签可能会更好。构建你想藏匿的东西。做出承诺。为该提交创建标记。然后将您的分支回滚到HEAD^。现在,当您想重新申请该存储时,可以使用git cherry-pick -n tagname-n--no-commit)。

答案 5 :(得分:23)

所以,我不确定为什么在这个话题上有这么多的疑惑。我可以同时使用push和已弃用的save name a git stash,也可以使用正则表达式将其apply撤回:

Git隐藏方法以使用名称来应用

$ 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动画。

Animated GIF showing a git stash apply using an identifiable name.

事件顺序

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命令有效。

这甚至有意义吗?

坦率地说,我不确定这种方法的好处是什么。给存储区起一个名字是有价值的,但取回却没有。也许编写shelve and unshelve脚本的脚本可能会有所帮助,但是仅按名称弹出隐藏项仍然很容易。

$ git stash pop 3
$ git stash apply 3

在我看来,这比正则表达式更容易。

答案 6 :(得分:22)

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

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

答案 7 :(得分:18)

我在.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

答案 8 :(得分:8)

别名

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

用法

git sapply "<regex>"

  • 与Git for Windows兼容

编辑:我坚持原来的解决方案,但我明白为什么大多数人更喜欢Etan Reisner的版本(上图)。所以只是为了记录:

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

答案 9 :(得分:7)

不幸的是,git stash apply stash^{/<regex>}不起作用(它实际上没有搜索存储列表,请参见accepted answer下的注释)。

这里是直接替换项,它们通过正则表达式搜索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 $?

请注意variable expansion exploits,因为我不确定--grep=$1部分。应该是--grep="$1",但我不确定是否会干扰正则表达式分隔符(我愿意接受建议)。

答案 10 :(得分:6)

这个答案很大程度上归功于KlemenSlavič。我会对已接受的答案发表评论,但我还没有足够的代表:(

您还可以添加一个git别名来查找存储引用,并将其用于show,apply,drop等其他别名。

[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定位最新的存储而不是像预期的那样失败。

答案 11 :(得分: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

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

答案 12 :(得分:4)

使用小型bash脚本查找存储的编号。称之为&#34; gitapply&#34;:

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是您想要的藏匿名称的子字符串。

答案 13 :(得分: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''
    }
}

More details here

答案 14 :(得分:2)

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

注意:正如凯文所说,you should use tags and cherry-picks instead.

答案 15 :(得分:2)

对于除了藏匿创建之外的所有内容,我通过引入fzf作为依赖关系来提出另一种解决方案。建议花5分钟的时间来介绍它,因为它总体上提高了生产力。

无论如何,他们examples page提供藏匿搜索的相关摘录。更改sciptlet以添加其他功能(如存储应用程序或删除)非常容易:

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
}

答案 16 :(得分:1)

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

答案 17 :(得分:1)

在我的鱼壳中

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

使用

gsap name_of_stash

答案 18 :(得分:1)

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

答案 19 :(得分:0)

那呢?

=> true

答案 20 :(得分: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"

希望对您有帮助!

答案 21 :(得分:-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. 如果您使用的是 zsh 或 oh-my-zsh,则需要编辑您的 ~.bashrz~.zshrc,添加以下别名:
# 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”的 stash 中提取您的 stash 更改:sitsh

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