2022年7月修订: 时间(和 Git)已经过去,取决于您的 Git 版本,以下大部分内容可能已不再准确。其中最重要的变化之一是现在有了 git stash push
和 git stash create
命令。请参见脚注和评论。
正如Xavier Álvarez指出和codeWizard写道的那样,在这里完全避免使用git stash
可能是明智的选择。例如,我会考虑使用单独的git fetch
和git rebase
步骤(参见Xavier的答案),并注意到rebase现在具有--autostash
选项,它就是你想要的,只是不能直接通过git pull
便捷脚本使用。1
话虽如此,还是有方法能够做到你所说的。这有点棘手。如果git stash save
有一个类似于git commit --allow-empty
的“force”选项,那么这将更容易,但它没有这样的选项。2相反,你可以检测git stash save
是否推送了一个新的 stash。如果git stash save
有一个指示它是否推送了 stash 的退出状态,那么这也将更容易,但不幸的是它没有。这意味着我们必须完全依靠另一种技巧。我们从两个事实开始:git rev-parse
从“引用”中找到 SHA-1,并且git stash
使用一个特定的引用。
git rev-parse
命令会将任何引用转换为SHA-1:
$ git rev-parse refs/remotes/origin/master
2635c2b8bfc9aec07b7f023d8e3b3d02df715344
引用(Reference)通常以refs
开头,是指向某个SHA-1 ID的名称。最常见的引用是分支:refs/heads/branch
,你可能也使用过标签:refs/tags/tag
,以及类似origin/master
这样的远程跟踪分支,它的完整名称是refs/remotes/origin/master
。
stash
脚本使用refs/stash
,因此我们可以简单地运行git rev-parse refs/stash
。3 我们想在运行git stash save
之前运行它,然后再次运行git stash save
。如果输出发生变化,则git stash save
步骤必须已经将一个新的存储推入了存储堆栈。
我们必须小心一点,因为如果存储堆栈为空(因为上一个存储被弹出或删除,或者尚未创建任何存储),git rev-parse
将会给出错误消息并且不会产生SHA-1:
$ git rev-parse refs/stash
fatal: ambiguous argument 'refs/stash': unknown revision or path not in
the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
因此,我们实际上需要使用
git rev-parse -q --verify refs/stash
,如果引用不存在,则会静默地不产生任何内容,然后我们只需要在使用结果的任何Shell脚本中小心处理即可。
oldsha=$(git rev-parse -q --verify refs/stash)
git stash -q save
newsha=$(git rev-parse -q --verify refs/stash)
if [ "$oldsha" = "$newsha" ]; then
made_stash_entry=false
else
made_stash_entry=true
fi
... all of your other code goes here ...
if $made_stash_entry; then git stash pop; fi
1git pull
命令基本上是git fetch
后跟git merge
的简写,或者如果你告诉它,可以运行git fetch
后跟通常更合适的git rebase
。不过,如果将它分成两个单独的步骤,你就能获得更多控制权,同时还能在合并或变基之前检查传入的更改。
编辑,2022年7月:git pull
现在不再是脚本,并且自动暂存与其一起工作。其中有过渡状态。
2你可以使用相对较新的create
和store
子命令有效地强制创建存储:创建一个存储,然后存储结果SHA-1,即使没有要存储的内容,你也已经强制进行了存储。但并非每个人都更新了最近的git,因此对于脚本来说,依赖旧方式(或如前所述,根本不使用存储,特别是因为它在各种版本的Git中存在各种次要但令人讨厌的错误)可能更明智。
编辑,2022年7月:git stash
现在不再是脚本,并且有了新的选项和动词。请参阅注释。
3最好拼出完整名称,因为git rev-parse stash
将首先查找名为stash
的分支。总的来说,在编写别名或脚本时,对于所有引用都要拼出全名(必要时使用--
语法),以确保Git不会在奇怪的边角情况下执行它认为你的意思。