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


我总是觉得你可以做一个名字 git stash save stashname,你可以稍后申请 git stash apply stashname。但似乎在这种情况下发生的一切都是这样的 stashname 将用作藏匿描述。

有没有办法真正命名藏匿?如果没有,你会建议什么实现相同的功能?基本上我有一个小的藏匿,我会定期申请,但不想总是要打猎 git stash list 它的实际存储数是多少。


930
2018-06-29 21:33


起源


git stash push -m stashname 是个 当前语法。 git stash save stashname 已被弃用。 - SherylHohman
git stash push -m stashname在2.8.0.windows.1中不起作用。 - Jac


答案:


您实际上可以使用git的正则表达式语法通过名称查找存储来寻址对象:

stash^{/<regex>}
:/<regex>

例如,使用保存名称保存存储时:

git stash save "guacamole sauce WIP"

...您可以使用正则表达式来处理该存储:

git stash apply stash^{/guacamo}

这将应用与正则表达式匹配的最年轻的存储 guacamo。这样,您不必知道堆栈中存储的数字,您只需要知道它的名称。这没有更简洁的语法,但您可以在您的。中创建别名 .gitconfig 文件:

[alias]
sshow = "!f() { git stash show stash^{/$*} -p; }; f"
sapply = "!f() { git stash apply stash^{/$*}; }; f"

然后你可以使用 git sapply <regex> 申请该藏匿(不丢弃)。
 然后你可以使用 git sshow <regex> 显示:文件已更改,插入和删除

编辑: 道具 这个StackOverflow的答案 关于如何在git别名中使用bash参数。

编辑2: 这个答案曾经包含 drop 和 list 别名,但我已经删除了它们,因为 drop 要求 stash@{n} 语法而 list 根本没有过滤藏匿处。如果有人知道如何将存储SHA-1哈希解析为存储引用,那么我也可以实现其他命令。

编辑3: 每 isyi我的建议我添加了一个补丁标记,以显示隐藏的内容在显示时的内容。


1149
2017-07-27 13:17



该 stash^{/foo} 语法实际上并不匹配所有存储条目。看看它到底做了什么,做一个 git stash log。这是它将匹配的条目。 - Ikke
如果您将'-p'附加到git stash show,您还可以看到对文件的实际编辑。 sshow命令如下: sshow = "!f() { git stash show stash^{/$*} -p; }; f" - isyi
确实。尽管存在所有的支持,但这个答案似乎完全不正确。存储列表无法搜索 ^{/pat} 因为它们没有相互连接。 - Etan Reisner
@KrofDrakula我想修改你的答案,但你的方法与我的完全不同。您使用的语法 <rev>^{/<text>} 遍历git的 日志 就像 git log stash 确实。但是这种方式只能访问最后保存的存储!另一种方法是使用git 引用日志, 喜欢 git reflog stash 要么 git stash list 确实。这使您可以访问所有可用的藏匿处。您的回答的问题是您声称可以遍历所有可用的藏匿处,但您没有。另见 log vs reflog。 - Vlastimil Ovčáčík
嘿,我找到了一个非常hacky但工作方式来git pop /应用“命名存储”(带有自定义消息的存储)。您可以使用git log来获取您的存储引用,如下所示: git log -g stash --grep="Your stashes message" --pretty=format:"%gd"  因此,如果你想要弹出最年轻的藏匿“命名”“Foo”,你可以做到 git stash pop $(git log -g stash --grep="Foo" --pretty=format:"%gd") - Jan Nash


这是你如何做到的:

git stash save "my_stash"

其中“my_stash”是藏匿名称...

一些更有用的知识:所有的存储都存储在一个堆栈中。 输入 :

git stash list

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

要应用存储并将其从存储堆栈中删除,您可以给,

git stash pop stash@{n}

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

git stash apply stash@{n}

其中n在隐藏的索引中发生变化。


322
2018-03-04 08:18



这不回答这个问题。默认情况下,您最终会得到一堆数字用于存储,但这并不能解答您如何轻松识别名称。 - GoodSp33d
由于它是简单的命令,我添加了一些更有用的信息。但你是对的,我现在已经编辑了我的答案。希望现在相关:) - Sri Murthy Upadhyayula
这实际上仍然没有回答如何在以后应用具有该名称的存储的问题。提问者已经知道了 git stash save。这实际上是问题的第一行。 - Cubic
OP明确地试图避免用于自定义名称的笨拙命名的存储@ {n}名称。 git stash apply <custom-name> - stewSquared
这不是无关紧要的。它是有益的。 - reversiblean


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

git stash branch <branchname> [<stash>]

从手册页:

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

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

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


64
2018-06-29 22:34



由于分支在git中相当便宜,这个建议对我来说最有用。 - Jayan
当然,但是如果你想继续在不同的分支中重新应用这个藏匿,就像OP要求的那样,这无济于事。你不得不挑选自己的头脑。 - stewSquared
@stewSquared为什么不能一个rebase --onto工作? - Gauthier


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


31
2018-06-29 21:39



绝对喜欢这种方法,感觉有点干净 named commit 在某个地方闲逛。只有轻微的烦恼是它不会在樱桃选择中保留并保留在差异中,这意味着在下一次提交期间需要手动不签入。 - Aditya M P
这是最接近的。我想我会为此制作一些别名。我不喜欢将描述用作“名称”。 - stewSquared


git stash save 是 弃用 现在,你可以使用 git stash push -m "message" 

你可以这样说:

git stash push -m "message" 

其中“消息”是你的藏匿名称......


15
2018-03-29 15:08



文档显示 push 而不是 save 句法: git stash push - SherylHohman


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

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

# re-apply it later
git apply some.patch

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


12
2017-11-10 16:06



完美的我的用例:) - tamj0rd2


别号

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"

7
2017-11-26 22:51



运用 awk -F: '{print $1}' 将彻底消除对sed的需求。为什么将它包装在一个函数中呢?并使用 awk -F: -vpat="$*" '$0 ~ pat {print $1}' 应该允许放下grep。虽然可能需要稍微不同的模式引用。 - Etan Reisner
@EtanReisner:您的代码段输出多行。 - Vlastimil Ovčáčík
采取行动 {print $1; exit} 在第一个匹配的行之后退出。 - Etan Reisner
@EtanReisner:经过一些测试后我可以摆脱sed,但是包装和grep保持不变。 - Vlastimil Ovčáčík
你不需要grep,就像我说的模式引用可能会有所不同。我用包装器假设你的意思是shell功能?你从来没有解释为什么你认为你需要这样做所以我不能评论你是否真的这样做,但我相信你很可能不这样做。 (您可能需要直接手动调用shell而不是git stash,但可能甚至不需要。) - Etan Reisner


这个答案很大程度上归功于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定位最新的存储而不是失败,如人们所期望的那样。


5
2018-01-11 01:30



这对我有用,而接受的答案似乎不起作用(请参阅我对接受的答案的推荐) - Jan Rüegg