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


686

我在开发部门进行了一些未提交的更改,并使用对其进行了隐藏git stash,但是其中一些更改在那些已隐藏的更改中非常重要。有什么办法找回这些更改吗?

另外,自此以后,我对隐藏的代码文件进行了一些更改。

如果有可能,我是否有可能将隐藏的更改检索到新分支?


7
您是否尝试过使用“隐藏流行音乐”?
罗伯特

不。实际上我是git的新手。由于我不完全了解所有命令,因此我没有尝试任何其他操作!我不想失去那些改变。
Aswathy P Krishnan 2013年

33
如果您不想丢失隐藏的更改,请尝试使用“ git stash apply”。这会将隐藏的更改应用于您当前的分支,同时仍保留隐藏的内容。如果一切正常,将藏匿后,你可以将藏匿,使用“git的藏匿降”
罗伯特

2
@robert谢谢您提供的简单答案,而不是(对于新手而言)非常复杂的答案。
Saheel Godhane 2014年

Answers:


1178

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

只需签出要更改的分支,然后单击git stash apply。然后使用git diff查看结果。

在完成所有更改之后- apply看起来不错,并且确定不再需要存储空间- 然后使用git stash drop它来摆脱它。

我总是建议使用git stash apply而不是git stash pop。区别在于,可以apply将存储区保留下来以便于重试apply或查看等。如果pop能够提取存储区,它将立即也将其存储drop,并且如果您突然意识到想要将其存储在某个位置其他(在不同的分支中),或者使用--index或类似的东西,并不是那么容易。如果您愿意apply可以选择何时选择drop

但是,无论哪种方式,它都是非常小的,对于git的新手来说,它应该差不多。(并且您可以跳过所有其他步骤!)


如果您正在做更高级或更复杂的事情怎么办?

至少有三种或四种不同的“使用git stash的方式”。上面是针对“方法1”的“简单方法”:

  1. 您从一个干净的分支开始,正在进行一些更改,然后意识到您在错误的分支中进行了更改。您只想进行现在的更改,然后将其“移动”到另一个分支。

    如上所述,这是简单的情况。运行git stash save(或简单的git stash同一件事)。签出另一个分支并使用git stash apply。使用git相当强大的合并机制,这可以使git合并到您之前的更改中。 仔细检查结果(使用git diff),以查看是否喜欢它们,如果喜欢,则使用git stash drop放下藏匿处。你完成了!

  2. 您开始了一些更改并将其隐藏。然后,您切换到另一个分支并开始更多更改,而忘记了已隐藏的那些。

    现在,您要保留甚至移动这些更改,并也应用存储。

    实际上git stash save,您可以再次git stash进行更改,就像“堆叠”一样。如果这样做,则有两个存储区,一个存储区被称为stash-但您也可以编写stash@{0}-一个存储区stash@{1}。使用git stash list(随时)查看所有内容。最新的始终是编号最小的。当您使用时git stash drop,它将删除最新的,然后将其stash@{1}移到堆栈的顶部。如果您拥有更多,则原来的stash@{2}变为stash@{1},依此类推。

    您还可以apply再添加drop一个特定的存储区:git stash apply stash@{2},依此类推。删除特定的存储区,仅对编号较高的存储区重新编号。再说一次,没有数字的也是stash@{0}

    如果您堆积了很多储藏物,它可能会变得很杂乱(是我想要的储藏物stash@{7}还是它stash@{4}??等等,我只是推了另一个,现在是8和5?)。我个人更喜欢将这些更改转移到新的分支机构,因为分支机构具有名称,并且cleanup-attempt-in-December对我来说意义比得多stash@{12}。(该git stash命令带有一个可选的保存消息,这些消息可以提供帮助,但是以某种方式,我所有的存储都名为named WIP on branch。)

  3. (高级)在运行之前git stash save -p,您已经使用过,或仔细使用过git add和/或使用过git rm代码的特定位git stash save。在隐藏的索引/临时区域中有一个版本,在工作树中有另一个(不同)版本。您想保留所有这些。因此,现在您使用git stash apply --index,但有时会失败:

    Conflicts in index.  Try without --index.
    
  4. 您正在使用git stash save --keep-index以测试“将提交的内容”。这超出了这个答案的范围。请参阅此其他StackOverflow答案

对于复杂的情况,建议您首先提交一个“干净的”工作目录,方法是提交您现在所做的任何更改(如果需要,可以在新分支上)。这样,您正在应用它们的“某处”就没有其他任何东西了,而您只是在尝试隐藏的更改:

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 new branch for "apply"
git stash apply          # apply stashed changes; see below about --index

要记住的主要事情是“存储” 一个提交,它只是一个稍微“有趣/怪异”的提交,而不是“在分支上”。该apply操作将查看提交更改的内容,并尝试在您现在的任何位置重复执行。存放处仍将存在(apply保持存放处),因此您可以对其进行更多查看,或确定这是错误的放置位置,apply然后以其他方式再次尝试,或执行其他操作。


每当您有储藏室时,都可以git stash show -p用来查看储藏室中内容的简化版本。(此简化的版本仅查看“最终工作树”的更改,而不查看--index单独恢复的已保存索引更改。)git stash apply不带的命令--index现在尝试在工作目录中进行相同的更改。

即使您已经进行了一些更改,也是如此。该apply命令很乐意将隐藏项应用到修改后的工作目录(或至少尝试将其应用)。例如,您可以执行以下操作:

git stash apply stash      # apply top of stash stack
git stash apply stash@{1}  # and mix in next stash stack entry too

您可以在此处选择“应用”顺序,挑选出特定的存储区以特定的顺序进行应用。但是请注意,每次您基本上都在进行“ git merge”,并且正如合并文档警告的那样:

不建议运行git merge并进行不重要的未提交更改:尽管可能,但可能会使您处于在发生冲突的情况下很难退出的状态。

如果您从一个干净的目录开始并且仅执行几个git apply操作,则很容易撤消:用于git reset --hard返回到干净状态并更改您的apply操作。(因此,对于这些复杂的情况,我建议首先从一个干净的工作目录开始。)


那最糟糕的情况呢?

假设您正在做很多Advanced Git Stuff,并且已经制作了一个存储,并且想要这样做git stash apply --index,但是再也无法应用带有的存储的Stash --index,因为自保存以来,分支的分支已经太多了。

git stash branch是为了什么。

如果你:

  1. 检查出您完成原始操作时的确切提交stash,然后
  2. 创建一个新分支,最后
  3. git stash apply --index

重新创建更改的尝试肯定会成功。这是做什么的。(然后,由于成功应用了存储,它会删除该存储。)git stash branch newbranch


最后几句话--index(到底是什么?)

做什么--index很容易解释,但内部有点复杂:

  • 进行更改后,您必须先更改git add(或“登台”)它们commit
  • 因此,当您运行时git stash,您可能已经编辑了文件foozorg,但仅上演了其中一个。
  • 因此,当您要求退回存储时,如果它git addadded 而不 git add是非添加的东西,则可能会很好。也就是说,如果您在执行之前先add编辑foo但没有zorg回来stash,那么最好使用完全相同的设置。上演过的,应该再次上演;已修改但未上演的内容应再次修改但不可上演。

尝试以这种方式设置事物的--index标志apply。如果您的工作树是干净的,通常就可以了。但是,如果您的工作树已包含added,则可以看到这里可能有一些问题。如果省略--index,则该apply操作不会尝试保留整个暂存/未暂存的设置。相反,它只是使用“存储袋”中的工作树提交来调用git的合并机制。如果你不关心保留上演/不分阶段,留下了--index让人们更方便的git stash apply以做它的事。


2
我不明白你的评论。你是说:你跑了git stash pop?还是您的意思是:您编辑了一些文件,但是还没有git stash再次运行?还是您完全是其他意思?
torek

1
是。注意,在我的(长期)编辑中,我建议在apply存储之前提交您现在拥有的内容。你不必这样做,但它使事情变得更简单了,你去看看。以后,您可以rebase -i用来压缩多个提交,或挑选特定的更改,或进行其他任何操作。
torek 2013年

1
是的git stash apply --index(记住两个破折号)。如果不考虑--index,没什么大不了的;唯一的目的--index是保持分段/非分段设置。(首先可能没有任何特殊的设置。)然后进行其他操作git status,然后根据需要进行添加/提交等操作。当(且仅当)已完成所有存储时,请使用该存储git stash drop
torek 2013年

1
只要您保存(不保存drop或不保存pop)存储,就可以始终确保原始存储的代码在提交时是安全的,因为存储提交!如果你想要把它找回来正好,但在一个分支,使用git stash branch(参见上面的那款,或临Git的书尚雅的答案)。然后,您可以git checkout分支,或git cherry-pick提交关闭分支等
托雷克

2
@ChuckWolber:Git的命名约定还有很多不足(我们可以为“ remote”,“ tracking”和“ branch”这两个词赋予多少种不同的含义?)。值得注意的是,您可以将隐藏项应用到与原始隐藏项无关的内容。
torek

56
git stash pop

将一切恢复原状

如注释中所建议,您可以使用git stash branch newbranch将隐藏项应用到新分支,这与运行相同:

git checkout -b newbranch
git stash pop

谢谢您的帮助。我可以将这些更改放入新的分支吗?现在我在开发部门
Aswathy P Krishnan

3
git stash branch newbranch,将使用隐藏的更改创建一个新分支。
罗伯特

3
@robert:git stash branch newbranch确实可以做到;但要注意,它与其父集上创建新的分支到提交那是HEAD当时stash已完成。换句话说,它是为您在经过长时间的黑客会议或诸如此类的事情之后回来,盯着混乱的地方,并决定“我应该把它放在树枝上,而不是藏在里面” :-)
torek

我已经编辑了我的问题。如果可能的话,我想将这些更改添加到新分支中。
Aswathy P Krishnan

1
有时您只想要TLDR答案:)
sachinruk

23

为简单起见,您有两个选择可以重新应用存储:

  1. git stash pop -恢复到已保存状态,但会从临时存储中删除存储。
  2. git stash apply -恢复到保存状态并保留存储列表,以备日后重用。

您可以在本文中详细了解有关git隐藏的信息。


19

要检查您的隐藏内容:

git存储列表

从存储列表中应用特定的存储号:-

git stash apply stash @ {2}

或仅应用第一个存储区:

git stash pop

注意: git stash pop会从存储列表中删除该存储,而git stash不会应用。因此,请相应地使用它们。


2

在Mac上,这对我有用:

git stash list(查看所有的stash)

git stash list

git stash apply(只是您要从存储列表中获取的数字)

像这样:

git stash apply 1

0

您可以使用“ git stash”存储未提交的更改,然后使用“ git checkout -b”检出到新分支,然后应用隐藏的提交“ git stash apply”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.