如何恢复隐藏的未提交更改

1002

我在开发分支中有一些未提交的更改,我使用了 git stash 命令将它们存储,但其中有一些非常重要的更改被存储了起来。有没有办法恢复这些更改?

另外,我在存储的代码文件上进行了一些更改。

如果可能,有没有机会将存储的更改检出到一个新的分支中?


12
你试过使用“stash pop”吗? - robert
1
不,实际上我是新手,对于所有的命令都不是很清楚所以我没有尝试其他的东西!我不想失去那些更改。 - Aswathy P Krishnan
56
如果你不想丢失暂存的更改,可以尝试使用 'git stash apply'。这将把暂存的更改应用到你当前的分支上,同时仍保留着暂存。如果应用更改后一切正常,你可以使用 'git stash drop' 删除暂存。 - robert
8个回答

1689

简单问题的简单答案是git stash apply

只需切换到您想要更改的分支,然后使用git stash apply。然后使用git diff查看结果。

完成所有更改后-apply看起来很好,并且您确定不再需要stash-然后使用git stash drop将其删除。

我总是建议使用git stash apply而不是git stash pop。区别在于apply会保留stash以便轻松重试apply,或查看等等。如果pop能够提取stash,它将立即drop它,如果随后意识到您想在其他地方(在不同的分支中)或使用--index等提取它,则不那么容易。如果您使用apply,则可以选择何时drop

虽然这些都是小问题,但对于 Git 新手来说,影响不大。如果您是新手,请跳过其余部分!


如果你在做更高级或更复杂的操作怎么办?

至少有三到四种“使用git stash”的方法。上面是“方式1”,即“简单的方式”:

  1. 你从一个干净的分支开始,正在进行一些更改,然后意识到你在错误的分支上工作。你只想把现在的更改“移动”到另一个分支。

这是简单的情况,如上所述。运行git stash save(或普通的git stash,同样的事情)。切换到另一个分支并使用git stash apply。这使得Git合并您之前的更改,使用Git的相当强大的合并机制。仔细检查结果(使用git diff)以查看是否喜欢它们,如果喜欢,使用git stash drop删除stash。完成!

  1. 你开始了一些更改并将它们放入了stash。然后你切换到另一个分支开始了更多的更改,忘记了你有stash的更改。
现在您想保留甚至移动这些更改,并应用您的存储。您实际上可以再次使用git stash save,因为git stash会创建一个“堆栈”以保存更改。如果您这样做,您将有两个存储:一个称为stash(您也可以写成stash@{0}),另一个称为stash@{1}。随时使用git stash list查看它们。最新的始终是编号最低的。当您使用git stash drop时,它会删除最新的,并且之前的stash@{1}会移到堆栈顶部。如果您有更多,则之前的stash@{2}变为stash@{1},依此类推。
你可以使用git stash apply stash@{2}等方式来应用或者丢弃特定的存储,丢弃一个特定的存储只会重新编号高编号的存储。同样,没有编号的存储也是stash@{0}
如果你积累了很多存储,可能会变得相当混乱(我想要的存储是stash@{7}还是stash@{4}?等等,我刚刚又推送了一个,现在它们是8和5了吗?)。我个人更喜欢将这些更改传输到新分支,因为分支有名称,cleanup-attempt-in-December对我来说比stash@{12}更有意义。(git stash命令带有一个可选的保存消息,这些消息可以帮助,但不知怎么的,我所有的存储都被命名为WIP on branch。)
  1. (Extra-advanced) You've used git stash save -p, or carefully git add-ed and/or git rm-ed specific bits of your code before running git stash save. You had one version in the stashed index/staging area and another (different) version in the working tree. You want to preserve all this. So now you use git stash apply --index, and that sometimes fails with:

    Conflicts in index.  Try without --index.
    
  2. You're using git stash save --keep-index in order to test "what will be committed". This one is beyond the scope of this answer; see this other StackOverflow answer instead.

对于复杂的情况,我建议首先从一个“干净”的工作树开始,通过提交您现在所拥有的任何更改(如果您喜欢,可以在新分支上)来实现。这样,“应用它们的地方”就没有其他东西了,您只需要尝试存储的更改:
git status               # see if there's anything you need to commit
                         # uh oh, there is - let's put it on a new temp branch
git checkout -b temp     # create new temp branch to save stuff
git add ...              # add (and/or remove) stuff as needed
git commit               # save first set of changes

现在你处于一个“干净”的起点。或者可能更像这样:
git status               # see if there's anything you need to commit
                         # status says "nothing to commit"
git checkout -b temp     # optional: create a new branch for "apply"
git stash apply          # apply stashed changes; see below about --index

重要的是要记住,“stash”本质上就是一个提交(commit),只不过它是一个略微“有趣/奇怪”的提交,它并没有“在分支上”。应用(apply)操作会查看提交所做的更改,并尝试在当前位置重复这些更改。存储区(stash)仍然存在(apply 会保留它),因此您可以进一步查看它,或者决定这不是适合应用的正确位置并以不同方式再次尝试,或者其他操作。
任何时候,只要您有一个stash,您都可以使用git stash show -p来查看stash中的简化版本。(这个简化版本仅查看“最终工作树”更改,而不是--index单独恢复的保存索引更改。)命令git stash apply,不带--index,只是尝试在您的工作树中进行相同的更改。
即使您已经有了一些更改,这也是正确的。apply命令很乐意将stash应用于修改过的工作树(或者至少尝试应用它)。例如,您可以执行以下操作:
git stash apply stash      # apply top of stash stack
git stash apply stash@{1}  # and mix in next stash stack entry too

你可以在这里选择“应用”顺序,挑选特定的贮藏来按照特定的顺序应用。但请注意,每次你基本上都在执行“git合并”,而正如合并文档所警告的那样:运行带有非平凡未提交更改的 git 合并是不鼓励的:虽然可能是可行的,但在冲突情况下很难回退到一个容易处理的状态。
如果您从一个干净的树开始,只是进行几个 git 应用操作,那么回退很容易:使用 git reset --hard 恢复到干净状态,并更改您的应用程序操作。(这就是为什么我建议首先在干净的工作树中开始这些复杂情况的原因。)

最糟糕的情况怎么办?

假设你正在进行大量高级Git操作,已经创建了一个存储,想要使用git stash apply --index,但是由于自从你保存它以来分支发散太多,因此无法再应用保存的存储。

这就是git stash branch的用途。

如果你:

  1. 检出你原始stash时所在的精确提交,然后
  2. 创建一个新分支,最后
  3. git stash apply --index

重现更改的尝试肯定会成功。这就是git stash branch newbranch的作用。(然后它删除了存储,因为它已成功应用。)


关于--index的一些最终说明(到底是什么?)

--index的作用很容易解释,但在内部有些复杂:

  • 当您进行更改时,必须在提交之前将它们git add(或“暂存”)。
  • 因此,当您运行git stash时,您可能已编辑了文件foozorg,但只暂存了其中一个。
  • 因此,当您要获取存储回来时,如果它git addadded的内容并且不git add未添加的内容,那就太好了。也就是说,如果在执行stash之前,您将foo添加,但没有添加zorg,那么最好保持相同的设置。应该再次暂存已经暂存的内容;修改但未暂存的内容应该再次修改,但不应该暂存。
apply 命令的 --index 标志会尝试进行这样的设置。如果您的工作树是干净的,通常情况下它会正常工作。但是,如果您的工作树已经有了一些 add 操作,那么可能会出现问题。如果省略 --index,则 apply 操作不会尝试保留整个暂存/未暂存的设置。相反,它只会使用 "stash bag" 中的工作树提交来调用 Git 的合并机制。如果您不关心保留暂存/未暂存的内容,则省略 --index 可以使 git stash apply 更容易实现其功能。

2
我不明白你的评论。你是指:你运行了 git stash pop 吗?还是你是指:你编辑了一些文件,但尚未再次运行 git stash?或者你是指完全不同的事情? - torek
2
是的。请注意,在我的(长)编辑中,我建议在apply一个存储之前先提交您现在拥有的内容。您不必这样做,但这使您查看事情变得更加简单。您可以使用rebase -i将多个提交压缩在一起,或稍后挑选特定的更改,或进行其他操作。 - torek
1
是的:git stash apply --index(记住两个破折号)。如果你省略了 --index,也没关系;--index 的唯一目的是保持暂存/未暂存的设置。(你可能一开始就没有任何特殊的设置。)然后使用 git status 等命令,根据需要添加/提交等操作。当(且仅当)你完成了所有的隐藏操作时,使用 git stash drop 来丢弃它。 - torek
2
只要您保留(不要“drop”或“pop”)stash,您始终可以在提交中安全地保存原始的stashed代码,因为stash 提交!如果您想确切地将其取回,但在分支上,请使用git stash branch(请参见上面的部分,或[Pro Git book](http://git-scm.com/book/ch6-3.html)在[Shunya's answer](http://stackoverflow.com/a/19005203/1256452)中)。然后,您可以`git checkout该分支,或者从该分支中git cherry-pick`提交等。 - torek
2
@ChuckWolber:Git的命名规则还有很大的改进空间(“remote”、“tracking”和“branch”这些词有多少不同的含义?!)。值得注意的是,您可以将一个存储应用于与原始存储无关的内容。 - torek
显示剩余7条评论

112
git stash pop

会把一切都恢复原位

如评论中所建议,您可以使用 git stash branch newbranch 将stash应用于新分支,这与运行以下命令相同:

git checkout -b newbranch
git stash pop

谢谢帮助。我可以将这些更改放到一个新分支中吗?现在我正在develop分支上。 - Aswathy P Krishnan
3
git stash branch newbranch会创建一个带有暂存更改的新分支。 - robert
3
@robert: git stash branch newbranch确实可以做到这一点;但请注意,它会创建一个新分支,并将其父提交设置为当时进行“stash”操作时的“HEAD”提交。换句话说,它适用于当您在一段漫长的编程会话后回来时,看着混乱的代码并决定“我应该把它放到一个分支上,而不是存储”。 :-) - torek
我已经编辑了我的问题。如果可能的话,我想把这些更改放到一个新分支中。 - Aswathy P Krishnan
1
@sachinruk 有时候吗?总的来说,人们不会为了文档而来到StackOverflow,这不是它的目的,我并不是在批评写得好的答案,也不是在为一行代码辩护。 - Mel Macaluso

42

要查看您的暂存内容:

git stash list

从暂存列表中应用特定的stash编号:

git stash apply stash@{2}

或者只应用第一个stash:

git stash pop

注意: git stash pop将从您的暂存列表中移除该stash,而git stash apply则不会。 因此,请根据需要使用它们。


37
为了简单起见,您有两种重新应用存储内容的选项:
  1. git stash pop - 恢复到保存的状态,但删除临时存储中的存储内容。
  2. git stash apply - 恢复到保存的状态,并将存储列表留作可能的后续重用。
您可以在这篇文章中详细了解更多关于git 存储的内容。

15

要恢复被存储的更改...您只需使用一个命令即可

git stash pop

查看暂存更改列表

git stash list

清除暂存更改
git stash clear

10

在Mac上,以下操作对我有效:

git stash list(查看所有隐藏的存储)

git stash list

使用 git stash apply 命令(加上要应用的备份列表中编号)

像这样:

git stash apply(只需从备份列表中选择相应的编号即可)

git stash apply 1

5
您可以使用以下命令储藏未提交的更改:
git stash

然后使用以下命令检出到一个新的分支:

git checkout -b

然后应用保存的提交:

git stash apply

0

就像很多人说的那样,执行git stash apply stash@{1}将会获取当前分支上的更改,但我不知道为什么对我不起作用。

对我来说,执行git stash apply stashNumber总是有效的。

例如,如果我想要检索存档编号1,这就是我如何做到的- git stash apply 1

PS:你可以使用pop代替apply..唯一的区别是apply不会删除stash,但是执行pop会删除你弹出的stashnumber。


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