如何按名称命名和检索Git存储?

2360

我该如何保存/应用一个有名字的git储藏(stash)? 我不想在 git stash list 中查找它的索引号。我尝试了 git stash save "my_stash_name",但这只会更改储藏的描述,对应的 git apply "my_stash_name" 是无效的。


195
git stash push -m stashname当前语法git stash save stashname 已被弃用。 - SherylHohman
3
简单的自定义 git 命令(链接到 gist)。用法:git bottle name,然后稍后使用 git apply name.patch,如果您想要更详细的解释和使用示例,请参见我的答案 - GrayedFox
3
有趣的是,大多数答案似乎与问题无关。Cameron的答案最接近,因为它提供了一个解决方法,并详细解释了为什么它有效。然而,显然问题的答案是否定的。你不能做到OP所问的,但有一个解决方法可以通过其描述性评论应用stash。这可能就是为什么没有答案被接受为答案,或者OP只是忘记选择一个。这是一个好问题,我很欣赏,因为当我找到它时,我正好在寻找答案。 - shawn1874
28个回答

2
这里有很多答案,但我认为提问者想要的等效功能没有被任何一个回答或评论完全囊括。
通过将git addgit diffgit rmgit 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文件来忽略它。值得一提的是:这个答案启发了我自己的答案,其中描述了补丁方法,但忽略了新文件中的更改将被排除在diff显示之外的问题。注意:由于该命令依赖于git add,因此它将无法捕捉git已经忽略的任何文件的更改。

1
之前的回答版本没有检查旧的补丁文件是否存在,并使用 git rm 安全地取消跟踪和删除该文件。现在已添加此内容,以确保我们不会意外跟踪和暂存补丁文件,然后立即使用硬重置命令将其删除。 - GrayedFox
很酷的技巧,我可能会用它 - 但你离开 OP 所问的实际存储库有什么原因吗? - Dean Radcliffe

2

在我的Fish Shell中

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

use

gsap name_of_stash


1
如果使用VSCode,一个快速的方法是打开命令面板(CTRL / CMD + SHIFT + P),然后输入“Pop Stash”,你就能够通过名称检索到你的贮藏,而不需要使用git CLI。

1
除了stash创建之外的所有内容,我建议引入fzf作为依赖项提供另一种解决方案。我建议花5分钟时间介绍一下它,因为它是一个非常好的提高生产力的工具。
无论如何,他们的示例页面中有一个相关的摘录,提供stash搜索。很容易将脚本更改为添加其他功能(如stash应用或删除)。
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
}

1
如果你正在使用ZSH,那么这个别名组合相当致命:
zstyle ':completion:*' completer _expand_alias _complete _ignored
alias gs="git stash push -u -m "
alias gsp='git stash pop'

基本上,您可以使用制表符来自动完成别名,然后您可以轻松地按名称命名和搜索您的git存储。这个push别名还将包括任何未跟踪的文件,我发现这很有帮助作为默认设置。

1

我认为没有办法按名称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

我怀疑如果您使用太多的stash(比如超过三个),那么您可能做错了些什么:

通常,Stash是用于工作中断而不是实现功能(您可以使用功能分支来实现)。

假设您正在开发某个功能A,然后发现必须修复一些问题B才能实现该功能A。您可能会这样做:

  1. git add --interactivepatch 部分功能A,并忽略解决问题B的更改。
  2. git commit 交互式选择到当前分支。
  3. 将未提交的更改(解决问题B)git stash
  4. 回到主分支或主干,可能要检出一个新分支以解决问题B。
  5. 在当前分支上git stash pop解决问题B的更改并进行提交。如果stash需要手动合并,则可能需要git stash drop
  6. 回到功能分支并将其重新基于解决问题B的分支。然后您就没有更多的stash了,但仍然可以在不同的分支上拥有功能A和问题B的修复。
你也可以先提交问题B的修复,然后再隐藏功能A的更改,但你已经明白了。

-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”的存储中拉取已存储的更改:sitsh

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接