如何按名称命名和检索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个回答

2176

保存带有消息的存储:

git stash push -m "my_stash_name"

另外一种选择(自v2.16起已被弃用):

git stash save "my_stash_name"

列出 stash

git stash list

所有隐藏的内容都存储在堆栈中。


要弹出(即应用并删除)第 n 个存储:

git stash pop stash@{n}

使用git stash pop无法按名称弹出(即应用和丢弃)一个存储(请参见脚注1)。

应用第 n 个存储:

git stash apply stash@{n}

按名称应用存储

git stash apply stash^{/my_stash_name}

注释-1:

  • 请参阅man git-stash部分中的apply

    与pop不同,可能是任何看起来像由stash push或stash create创建的提交。

  • 可能的解决方法(在git版本2.27和2.31上测试):

    git stash pop $(git stash list --pretty='%gd %s'|grep "my_stash_name"|head -1|gawk '{print $1}')


51
OP明确想要避免使用stash@{n}这种笨拙的名称来自定义名称。使用git stash apply <custom-name>命令来应用自定义名称。 - stewSquared
79
git stash push -m my_stash当前语法git stash save my_stash 已被弃用。 - SherylHohman
4
这很令人困惑。只有 @AdamB 回答了这个问题。 - kiedysktos
11
如果你正在使用Windows PowerShell,执行stash apply可能会出现错误,所以记得将其放在引号中:git stash apply "stash@{n}" - Naveen
6
我使用"git stash push -m my_stash"创建了一个隐藏存储区,然后执行"git stash apply my_stash"时出现了错误。通过"git stash apply stash^{/my_stash}"命令修复了问题,这个方法来自@Cameron McKenzie的另一个答案。 - Abinash Dash
显示剩余12条评论

752

git stash push -m "message" should be used instead of git stash save as the latter is deprecated since version 2.15.x/2.16. To retrieve the stash, you can use git stash list, which will output a list of stashes.

Usage example:

git stash push -m "message"

Here, "message" refers to the note for that particular stash.

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

然后你只需使用apply,并将stash@{index}作为参数传递:

git stash apply 1

参考资料 Git存储手册


11
文档显示使用 push 而不是 save 语法:git stash push - SherylHohman
44
这是真正的答案。不幸的是,在它上面有很多旧的答案。 - mas
1
有关较新的git stash push更多信息请查看:https://dev59.com/NFcP5IYBdhLWcg3wP32t#47231547 - VonC
6
在PowerShell中运行git stash apply stash@{1}命令时,你可能会收到一个错误提示:error: unknown switch 'e'。此时,请使用以下两种方法代替:git stash apply --index 1或者git stash apply 'stash@{1}'。如果非要使用原来的命令,需要用反引号转义大括号{}},像这样:git stash apply stash@{1}”。 - LosManos
5
为什么Git选择像stash@{1}这样的奇怪命名方式?这在命令行中很难输入。如果我们可以输入类似于git stash show -p @1这样的内容,将会更容易… - zerox
显示剩余5条评论

228

如果您只是想找一个轻量级的方法来保存部分或全部正在进行的工作副本更改,并在需要时重新应用它们,那么可以考虑使用补丁文件:

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

# re-apply it later
git apply some.patch

有时我会想是否应该为此使用" stash ",但当我看到上面的疯狂事情时,我对自己正在做的感到满意 :)


8
没问题!谢谢。我也更新了我的 .gitignore 文件,忽略了 .patch 文件,现在可以愉快地打尽可能多的补丁了。 - LINGS
4
我可以看出问题背后的意图,即每次从主分支中取出一个新分支时,需要应用一些本地更改并将其暂存而不提交。因此,也许应该纠正问题,接受这个答案作为解决方案。这很简单。 - Karthick Meenakshi Sundaram
2
好的备选方案(替代stash)。 - isapir
1
我认为我们可能需要使用 git apply --3way some.patch 来增强这个答案。这更类似于传统的 git stash apply 方法。否则,冲突可能会导致补丁应用失败。 - Vance Palacio
6
我不相信这会创建新文件。 - james emanon
如果您不将新文件暂存,那么它们将不会被包含在git stashgit diff中。如果您在暂存之前将它们暂存,那么它们将被包含在内。 - cincodenada

142

如果您认为这很重要,您可以将存储转换为分支:

git stash branch <branchname> [<stash>]

从手册中获取:

此命令创建并检出一个名为<branchname>的新分支,该分支从创建<stash>时的提交开始,将记录在<stash>中的更改应用于新的工作树和索引,如果成功完成,则删除<stash>。如果没有给出<stash>,则将应用最新的密藏。

如果您运行了git stash save命令的分支已经发生足够的更改,导致使用git stash apply失败,那么此命令就会很有用。因为这个密藏被应用在当时HEAD为git stash运行时的提交之上,它可以无冲突地还原最初的存储状态。

您稍后可以将这个新分支重新基于某个其他位置,该位置是您存储时的子孙节点。


3
既然在 Git 中创建分支非常便宜,对我来说这个建议非常有用。 - Jayan
9
可以,但这并不有助于您以后想在不同的分支中反复应用此存储库,就像OP所问的那样。您将不得不挑选其头。 - stewSquared
@AdamDymitruk 有没有办法在不弹出(像 git stash apply 一样)的情况下执行此操作并保留存储? - Kasun Siyambalapitiya
很奇怪,当我尝试这个时候,我得到了一个错误消息,说我的一个文件将在检出时被覆盖,我应该提交或存储(!)我的更改。git stash push -m 'name'起作用了。 - wortwart

88

我在我的.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_" 是什么? - Sam Hasler
4
@SamHasler只是一些随机的独特字符串。如果您想知道stash是使用常规git stash还是这些函数创建的,可以参考这些内容。 - iWheelBuy
1
别名爱好者的优雅解决方案 - therealbigpepe
1
这些很棒!顺便说一下,你可以直接将它们放在.gitconfig中: stashput = "!f() { git stash push -m "stash_name_$1"; }; f".
stashget = "!f() { git stash apply $(git stash list | grep 'stash_name_$1' | cut -d: -f1); }; f". 然后在你的sh配置文件中(例如.bashrc或.bash_aliases)添加以下内容: ## git stash by name. alias gsp="git stashput " alias gsg="git stashget ". 现在你就可以在命令行上像这样使用它了:prompt# gsp localchanges. prompt# gsg localchanges.
- dyodji
2
我会执行 grep -m 1 "zsh_stash_name_$1",这样如果同一个名称被多次使用,它就会返回第一个结果:https://dev59.com/j2445IYBdhLWcg3wJ298#5013198 - pgarciacamou
1
这个答案应该排在最前面!!!这是最好的答案!! - ssppjj

69

所以,我不确定为什么在这个话题上会有那么多的困惑。我可以使用push和已弃用的save命名一个git stash,并使用正则表达式来使用apply将其取回:

Git存储方法使用名称应用

$ git stash push -m "john-hancock"

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

如前所述,save命令已被弃用,但仍可使用,因此您可以在无法使用push调用更新旧系统的情况下使用它。与push命令不同,save不需要使用-m开关。

// 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命令在stash之后显示4个文件,这意味着stash和隐式硬重置起作用了
  5. git stash apply stash^{/john-hancock}运行
  6. ls命令列出5个文件,显示example.html文件已经恢复,这意味着git stash apply命令起作用了。

这有意义吗?

坦白地说,我不确定这种方法的好处是什么。给stash命名确实有价值,但是检索没有。也许对于脚本保留和取消保留过程有帮助,但通过名称弹出stash仍然更容易。

$ git stash pop 3
$ git stash apply 3

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


2
你的回答是这个的更全面版,而该回答本身是对最初被接受的回答的重新陈述。 (请参见评论) - Michael
2
如果我发布了错误的内容会感到尴尬。我看不到最初被接受的已删除答案,可能是因为它已被删除。最大的问题是我无法使其始终正常工作,就像您可以从动画GIF中看到的那样。我将重新开始思考并查找原因,看看为什么它在不应该工作时却能正常工作。 - Cameron McKenzie
当两个存储名称相同时会发生什么? 1.两个存储都会应用吗? 2.最近的存储会应用吗? 3.最旧的存储会应用吗? - U R
1
你是如何从终端会话中创建那个动态GIF的? - U. Windl
我使用 Camtasia 录制了窗口,它有“另存为动画 GIF”选项。我觉得动画 GIF 是 1998 年互联网上被遗忘的珍宝。 - Cameron McKenzie
1
git stash push -m "john-hancock" -a 对我没用,相反,使用 git stash push -m "john-hancock" --include-untracked 可以将未跟踪/新添加的文件包含在存储中。干杯。 - Sid

65

Stash(储藏)并不像你想的那样是一种永久性的东西。你可能最好使用提交时的标签。构建出你希望储藏的内容,将其作为一个提交提交。为该提交创建一个标签。然后将你的分支回滚到HEAD^。现在当你想要重新应用这个储藏时,可以使用git cherry-pick -n tagname-n--no-commit)。


1
绝对喜欢这种方法,感觉更加清晰,只需要在某个地方挂一个“命名提交”。唯一的小烦恼是,在cherry pick时它不会被提交,而是留在差异中,这意味着下次提交时需要手动将其排除。 - Aditya M P
1
这是最接近的。我想为此创建一些别名。我不喜欢使用描述作为“名称”。 - stewSquared
1
很遗憾,它会添加到索引并且您需要重置,有人应该打补丁来添加 --no-stage 选项!相关链接:https://dev59.com/dlwY5IYBdhLWcg3wq5fl#32333564 - Ciro Santilli OurBigBook.com
1
@CiroSantilliOurBigBook.com 也有同样的想法,但是 git reset @ 很容易操作。 - Flip

54

使用git stash push -m aNameForYourStash命令进行保存。然后使用git stash list命令查看要应用的储藏编号(index)。最后使用git stash pop --index 0命令弹出储藏并应用它。

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


1
您的答案在名义上是最高评分答案,考虑到当前语法下关于 git stash {push,save}此评论 - Michael

43

这个怎么样?

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

2
听起来好像以前那个被接受的答案,但现在已经被删除了。 - Michael
嗯,那为什么它被删除了? - AdamB
1
我不知道,因为我没有发布答案,也没有10,000的声望,但我认为这与评论中说它不起作用有关:很遗憾git stash apply stash^{/<regex>}不起作用(它实际上并没有搜索存储列表,请参见被接受的答案下的评论)。 - Michael
1
  1. 运行 git stash list 命令,它会显示所有存储的进度,并附带它们的索引号。
  2. 接着运行 git stash apply 0 命令,其中的 0 是我从第一个命令中查找到的索引号。
- ambidexterous

27

保存一个带有名称的Git暂存

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

按名称应用git stash

$ git stash apply stash^{/say-my-name}

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