279

我有一个小补丁保存在我的 git stash 中。我已经将它应用到我的工作副本中,使用git stash apply. 现在,我想通过反向应用补丁来取消这些更改(有点像git revert会做的事情,但针对存储)。

有谁知道如何做到这一点?

澄清:我的工作副本还有其他变化。我的特殊情况很难描述,但您可以想象隐藏中的一些调试或实验代码。现在它在我的工作副本中与其他一些更改混合在一起,我想看看有没有来自存储的更改的效果。

stash 目前似乎不支持此功能,但 agit stash apply --reverse将是一个不错的功能。

4

13 回答 13

212

根据git-stash 手册页,“存储被表示为一个提交,其树记录工作目录的状态,其第一个父级是HEAD创建存储时的提交”,并git stash show -p为我们提供“记录在stash 作为隐藏状态与其原始父级之间的差异。

要保持其他更改不变,请git stash show -p | patch --reverse按以下方式使用:

$ git init
Initialized empty Git repository in /tmp/repo/.git/

$ echo Hello, world >messages

$ git add messages

$ git commit -am 'Initial commit'
[master (root-commit)]: created 1ff2478: "Initial commit"
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 messages

$ echo Hello again >>messages

$ git stash

$ git status
# On branch master
nothing to commit (working directory clean)

$ git stash apply
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   messages
#
no changes added to commit (use "git add" and/or "git commit -a")

$ echo Howdy all >>messages

$ git diff
diff --git a/messages b/messages
index a5c1966..eade523 100644
--- a/messages
+++ b/messages
@@ -1 +1,3 @@
 Hello, world
+Hello again
+Howdy all

$ git stash show -p | patch --reverse
patching file messages
Hunk #1 succeeded at 1 with fuzz 1.

$ git diff
diff --git a/messages b/messages
index a5c1966..364fc91 100644
--- a/messages
+++ b/messages
@@ -1 +1,2 @@
 Hello, world
+Howdy all

编辑:

对此的轻微改进是使用git apply代替补丁:

git stash show -p | git apply --reverse

或者,您也可以git apply -R用作git apply --reverse.

最近发现这个真的好用。。。

于 2009-06-20T15:39:33.197 回答
157
git checkout -f

将删除任何未提交的更改。

于 2016-11-06T05:44:31.477 回答
89

git stash[save]获取您的工作目录状态和索引状态,并将它们隐藏起来,将索引和工作区设置为HEAD版本。

git stash apply带回这些更改,因此git reset --hard将再次删除它们。

git stash pop带回这些更改并删除顶部隐藏的更改,因此git stash [save]在这种情况下将返回到以前的(弹出前)状态。

于 2009-06-19T23:22:22.600 回答
29

V1 git 手册页有一个关于取消应用存储的参考。摘录如下。

较新的 V2 git 手册页不包含对取消应用存储的任何引用,但以下内容仍然有效

取消应用 存储 在某些用例场景中,您可能希望应用存储的更改,做一些工作,然后取消应用最初来自存储的更改。Git 没有提供这样的 stash un-apply 命令,但可以通过简单地检索与 stash 关联的补丁并反向应用它来实现效果:

$ git stash show -p stash@{0} | git apply -R

同样,如果您不指定存储,Git 会假定最近的存储:

$ git stash show -p | git apply -R

您可能想要创建一个别名并有效地将 stash-unapply 命令添加到您的 Git。例如:

$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply
于 2015-04-23T06:30:01.043 回答
15

这早就到期了,但是如果我正确解释了问题,我找到了一个简单的解决方案,请注意,这是我自己的术语的解释:

git stash [save]将保存当前更改并将当前分支设置为“干净状态”

git stash list给出类似的东西:stash@{0}: On develop: saved testing-stuff

git apply stash@{0}将像以前一样设置当前分支 stash [save]

git checkout .将当前分支设置为之后 stash [save]

保存在 stash 中的代码不会丢失,可以git apply stash@{0}再次找到。

不管怎样,这对我有用!

于 2014-04-22T09:13:26.457 回答
8

如何反向应用存储?

除了其他人提到的,最简单的方法是先做

git reset HEAD

然后检查所有本地更改

git checkout . 
于 2019-09-15T16:39:44.587 回答
3

如果您不小心点击了存储,您可以按照我分享的图像取消存储。

于 2020-05-03T11:53:49.893 回答
2

除了@Greg Bacon 回答之外,如果二进制文件被添加到索引中并且是使用的存储的一部分

git stash show -p | git apply --reverse

可能导致

error: cannot apply binary patch to '<YOUR_NEW_FILE>' without full index line
error: <YOUR_NEW_FILE>: patch does not apply

添加--binary解决了这个问题,但不幸的是还没有弄清楚为什么。

 git stash show -p --binary | git apply --reverse
于 2017-10-17T19:59:51.880 回答
2

你可以应用两个命令

git reset .// 反转文件

然后

git checkout . // 反转更改

于 2021-07-16T20:15:55.547 回答
0

这是对上述答案的补充,但会根据消息添加对 git stash 的搜索,因为在保存新的存储时存储编号可能会更改。我写了几个 bash 函数:

apply(){
  if [ "$1" ]; then
    git stash apply `git stash list | grep -oPm1 "(.*)(?=:.*:.*$1.*)"`
  fi
}
remove(){
  if [ "$1" ]; then
    git stash show -p `git stash list | grep -oPm1 "(.*)(?=:.*:.*$1.*)"` | git apply -R
    git status
  fi
}
  1. 使用名称创建存储(消息)$ git stash save "my stash"
  2. 申请命名$ apply "my stash"
  3. 删除命名存储$ remove "my stash"
于 2018-06-05T16:21:21.373 回答
0

我自己也有类似的问题,我认为您需要做的就是git reset --hard您不会丢失您的更改或任何未跟踪的更改。

如果您阅读其中的文档,git stash --help说明 apply 是“像 pop,但不要从存储列表中删除状态”,因此状态仍然存在,您可以将其取回。

或者,如果您没有冲突,您可以git stash在测试更改后再次进行。

如果您确实有冲突,请不要担心,git reset --hard不会丢失它们,因为“应用状态可能会因冲突而失败;在这种情况下,它不会从存储列表中删除。您需要手动解决冲突并调用之后手动 git stash drop。”

于 2020-08-21T06:43:44.190 回答
0
git stash show -p | git apply --reverse

警告,并非在所有情况下都如此:“ git apply -Rman没有正确处理两次正确接触同一路径的补丁,这已在 Git 2.30(2021 年第一季度)中得到纠正。

这在将路径从常规文件更改为符号链接(反之亦然)的补丁中最为相关。

请参阅Jonathan Tan ( ) 的提交 b0f266d(2020 年 10 月 20 日(由Junio C Hamano 合并 -- --提交 c23cd78中,2020 年 11 月 2 日)jhowtan
gitster

apply: 当-R, 也反转部分列表

协助人:Junio C Hamano
签字人:Jonathan Tan

将符号链接更改为文件的补丁由 2 个部分编写(在代码中,表示为“struct patch”):首先,删除符号链接,其次,创建文件。

当使用 应用该补丁时-R,这些部分是相反的,因此我们得到:(1)创建符号链接,然后(2)删除文件。

这会在选中“删除文件”部分时导致问题,因为 Git 观察到所谓的文件不是文件而是符号链接,从而导致“错误类型”错误消息。

我们想要的是:(1)删除文件,然后(2)创建符号链接。

在代码中,这反映在检查删除previous_patch()时调用时的行为。 创建然后删除意味着当检查删除时,返回创建部分,触发模式冲突导致“错误类型”错误消息。check_preimage()
previous_patch()

但是delete then creation的意思是当检查delete的时候,previous_patch()returns NULL,所以对lstat检查delete模式,这就是我们想要的。

还有其他方法可以让补丁包含引用同一文件的 2 个部分,例如,在7a07841c0b中(“ git-apply:处理多次接触同一路径的补丁更好”,2008-06-27,Git v1.6.0-rc0 -合并)。" git apply -R" ( man )以同样的方式失败,这个提交使这个案例成功。

因此,在构建节列表时,在传递时以相反的顺序构建它们(通过添加到列表的前面而不是后面)-R

于 2020-11-09T19:53:25.213 回答
0

对我来说,我刚刚在签出时输入了错误的存储库名称。所以实际上没有远程拉。

因此,除了检查大小写之外,还要检查分支名称的拼写,或者更好的是,复制并粘贴它 - 以排除它。

于 2022-01-12T14:12:05.963 回答