Git stash: “无法应用于脏的工作树,请将您的更改暂存”

141

我试图使用git stash pop应用之前存储的更改,但是出现以下消息:

Cannot apply to a dirty working tree, please stage your changes

你对如何处理这个问题有什么建议吗?

12个回答

207

当我需要将暂存的更改应用到脏工作副本中,例如从暂存中弹出多个变更集时,我会使用以下命令:

$ git stash show -p | git apply -3 && git stash drop

基本上它

  1. 创建一个补丁(patch)
  2. 将其输入到应用程序(apply)命令中
  3. 如果存在冲突,则需要通过三方合并解决
  4. 如果应用程序(或合并)成功,它就会删除刚刚应用的存储项...

我想知道为什么 git stash pop 没有-f(force)选项,它应该与上面的一行代码完全相同。

同时,您可能希望将此一行代码作为 git 别名添加:

$ git config --global --replace-all alias.unstash \
   '!git stash show -p | git apply -3 && git stash drop'
$ git unstash
感谢@SamHasler指出的-3参数,它可以通过三方合并直接解决冲突。

1
Jo Factor,如果您的工作副本未被清理,git stash apply 将不会应用存储的更改。因此,您可以将 git stash show -p | git apply 视为某种强制暂存应用。 - muhqu
1
但是有帮助的是: git reset HEAD 然后在那之后取消隐藏的更改。 - Roger Alien
我已经使用这个解决方案有一段时间了。通常它是有效的,但有时在应用补丁时可能会出现棘手的问题,特别是如果补丁或底层代码库自创建补丁以来发生了很大变化。现在我更熟悉git了,我看到了sergey_mo下面的“git add、git stash、git reset”解决方案的美妙之处。 - Kirby
4
有一个文件出现了“错误:打补丁失败...补丁不适用”的提示。希望它会出现合并冲突提示。 - Aleksandr Dubinsky
2
这个解决方案对我没用,每个修改过的文件都会出现“错误:<file>与索引不匹配”的提示。然而,另一个解决方案有效。 - silvenon
显示剩余7条评论

64

我是这样做的:

git add -A
git stash apply

然后(可选):

git reset

2
+1!这比其他需要生成补丁或修改提交的解决方案更简单,而且它可以将您的本地更改安全地隔离开来,直到您确定更改已正确合并。 - peterflynn
我收到错误信息:“...已存在,无法检出...无法从存储中恢复未跟踪的文件”。 - Aleksandr Dubinsky
6
我使用了git add -u命令,它类似于-A但不会添加未跟踪的文件。 - Brad Cupit

9

您可以通过将所需的存储内容导出为补丁文件并手动应用,而无需隐藏当前更改来完成此操作。

例如,假设您想将 stash@{0} 应用于脏树:

  1. Export stash@{0} as a patch:

    git stash show -p stash@{0} > Stash0.patch
    
  2. Manually apply the changes:

    git apply Stash0.patch
    

如果第二步失败,您将需要编辑Stash0.patch文件来修复任何错误,然后再次尝试git apply


这对于我在一个目录上进行重构(删除它,并创建一个同名的符号链接)的情况是实用且可行的。Git 无法确定我的工作副本更改了什么。 - yclian
1
这个很好用。虽然我相当确定我的工作树是干净的,但我无法应用存储。 - Shiki
是的,我不得不删除关于二进制文件的行。 - Dorian

8
要么使用git reset清空你的工作目录,提交更改;或者,如果你想要将当前更改暂存,可以尝试以下命令:
$ git stash save "当前更改的描述"
$ git stash pop stash@{1}
这将会把当前更改暂存,并且从暂存栈中弹出第二个暂存。

5
但这个人希望同时应用这两个隐藏的物品! - Elazar Leibovich
@Elazar,你对问题的理解有些过度了。OP只是想应用之前的存储。如果你正确,当前的更改将被保留,解决方案可以重复:弹出,提交,重复。 - William Pursell
我认为他想让它们都未提交。但是,他也可以提交两次,然后将它们压缩成一个提交。 - Elazar Leibovich
我收到错误信息:“...已存在,无法检出...无法从存储中恢复未跟踪的文件”。 - Aleksandr Dubinsky

6
Mathias的解决方案绝对是最接近 git stash pop --force 的(而且真的,来吧Git开发人员,让我们得到这个选项!)
然而,如果您想仅使用Git命令执行相同的操作,可以执行以下操作:
  1. git commit -a -m“ Fixme”
  2. git stash pop
  3. git reset HEAD〜
换句话说,制作一个提交(我们永远不会推动它)来保存当前更改。现在,通过弹出存储区来清除您的工作区。现在,将存储区更改作为先前提交的修正提交。完成此操作后,您现在拥有两组更改组合在单个提交(“ Fixme”)中。只需重置您的检出以使其指向“ Fixme”提交之前的提交即可。 编辑 我刚意识到实际上更简单了,您可以完全跳过第三步,因此...
  1. git commit -a -m“ Fixme”
  2. git stash pop
  3. git reset HEAD〜
(提交当前更改,弹出存储的更改,重置第一个提交以获得未提交状态下的两组更改的组合。)

4

如果你像我今天一样发现自己处于这种情况,那么这些答案都不起作用。无论我执行了多少次 git reset --hard,都没有任何效果。我的解决方案(并非官方解决方案)如下:

  1. 找出存储的哈希值,使用 git reflog --all
  2. 将该哈希值与你感兴趣的分支合并

1
非常感谢,Yar。刚才在我的本地repo上,Git的奇怪行为让我感到沮丧,这正是你描述的同样问题。 - yclian

4

我还发现Mathias Leppich的解决方案非常有效,所以我在我的全局.gitconfig中为其添加了一个别名。

[alias]
        apply-stash-to-dirty-working-tree = !git stash show -p | git apply && git stash drop

现在我只需输入。
git apply-stash-to-dirty-working-tree

这对我来说非常有效。

(对于这个长的别名,你的使用体验可能会有所不同。但是当涉及到bash自动补全时,我喜欢多一点冗长的用法说明。)


3

如果你想将一个"脏"的代码库应用到一个存储库中,可以通过执行git add来暂存所做的更改,从而清理代码库。然后,你可以执行git stash pop并应用暂存的更改,没有问题。


2
您有已修改但尚未提交的文件。请执行以下操作之一:
git reset --hard HEAD (to bring everything back to HEAD)

或者,如果您想保存更改:

git checkout -b new_branch
git add ...
git commit
git checkout -b old_branch
git stash pop

2
@MikeCooper - 我想他只是意味着在提交之前添加任何你想要添加的内容。 - sscirrus

0

我试图运行这些命令时,大部分都无法正常工作;由于某种原因,它总是认为我对文件进行了本地更改。我无法应用藏匿,补丁无法应用,checkoutreset --hard也失败了。最终有效的方法是将藏匿保存为一个分支,使用git stash branch tempbranchname,然后执行普通的分支合并:git checkout mastergit merge tempbranchname。 来自http://git-scm.com/book/en/Git-Tools-Stashing

如果您想要一种更简单的方式来再次测试藏匿的更改,可以运行 git stash branch,它会为您创建一个新分支,检查您藏匿工作时的提交记录,将您的工作重新应用到该提交记录,如果成功应用,则删除藏匿。


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