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

我的开发部门有一些未经改变的变化,我把它们用git stash ,但是在那些藏起来的变化中有一些非常重要的变化。 有什么方法可以找回这些变化吗?

此外,我已经在自封的代码文件上做了一些改变。

如果可能的话,是否有机会将隐藏的修改恢复到新的分支?

容易回答的简单问题是git stash apply

只要看看你想要更改的分支,然后git stash apply 。 然后使用git diff来查看结果。

完成所有更改后, apply看起来不错,而且您确定不再需要存储 – 然后使用git stash drop来除去它。

我总是build议使用git stash apply而不是git stash pop 。 所不同的是, apply留下的存储周围,以方便重新apply或查看等,如果pop可以提取存储,它会立即drop它,如果你突然意识到你想要把它提取到其他地方(在不同的分支),或者用--index或者其他的东西,那不是那么容易。 如果你apply可以select何时drop

虽然这是一个很小的方法,对于一个新手来说,它应该是大致相同的。 (你可以跳过这一切!)


如果你正在做更高级或更复杂的事情呢?

至less有三四种不同的“使用git存储方式”,就像它一样。 以上是“方式一”,“方式一”:

  1. 你从一个干净的分支开始,正在做一些改变,然后意识到你在错误的分支中做着它们。 你只需要把你现在所做的改变和“移动”到另一个分支。

    如上所述,这是简单的情况。 运行git stash save (或普通的git stash ,同样的事情)。 检查出另一个分支并使用git stash apply 。 这得到了git在你以前的改变,使用git的相当强大的合并机制合并。 仔细检查结果 (使用git diff ),看看你是否喜欢它们,如果你这样做,使用git stash drop来放置存储。 你完成了!

  2. 你开始了一些变化,并把它们藏起来。 然后,你切换到另一个分支,并开始更多的变化,忘记你有藏起来的。

    现在你想要保留,甚至移动这些变化, 并且应用你的隐藏。

    事实上你可以把git stash savegit stash save一次,因为git stash会产生一个“堆栈”的变化。 如果你这样做,你有两个stash ,一个只是被称为stash – 但你也可以写stash@{0}和一个拼写stash@{1} 。 使用git stash list (在任何时候)看到他们全部。 最新的总是最低的编号。 当你git stash drop ,它会丢弃最新的东西,而stash@{1}会移动到栈顶。 如果您还有更多的话, stash@{2} stash@{1}将变成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命令带有一个可选的保存消息,这些可以帮助,但不知何故,我所有的藏品都只能WIP on branch上被命名为WIP on branch )。

  3. (Extra-advanced)在运行git stash save之前,你已经使用了git stash save -p ,或者仔细地用git add -ed和/或git rm -ed你的代码的特定位。 在隐藏的索引/暂存区域中有一个版本,而在工作树中有另一个(不同的)版本。 你想保留所有这一切。 所以现在你使用git stash apply --index ,并且有时会失败:

     Conflicts in index. Try without --index. 
  4. 您正在使用git stash save --keep-index以testing“将承诺什么”。 这个超出了这个答案的范围。 请参阅此其他StackOverflow答案 。

对于复杂的情况,我build议首先在一个“干净的”工作目录中,通过提交你现在所做的任何更改(如果你喜欢的话,在一个新的分支上)。 这样,你所应用的“某个地方”就没有其他的东西了,你只需要尝试一下变化:

 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它,并尝试不同的方式,或者不pipe。


任何时候你有一个藏匿的,你可以使用git stash show -p来看看git stash show -p在里面的简化版本。 (这个简化的版本只能看到“最终工作树”的变化, 而不是保存下来的索引变化 – 索引--index恢复) --index git stash apply ,没有--index ,只是试图在工作中做相同的改变,目录。

即使您已经有一些变化,情况也是如此。 apply命令很乐意将一个存储器应用到一个修改的工作目录(至less,试图应用它)。 你可以,例如,这样做:

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

您可以在这里select“申请”命令,挑出特定的包装以特定顺序应用。 但是,请注意,每次你基本上正在做一个“混帐合并”,并作为合并文件警告:

不鼓励git合并非重要的未提交的变更:尽pipe可能,但可能会让你处于一个冲突情况下很难退出的状态。

如果你从一个干净的目录开始,只做几个git apply操作,很容易退出:使用git reset --hard返回到clean状态,并改变你的apply操作。 (这就是为什么我build议首先从干净的工作目录开始,对于这些复杂的情况。)


那最糟糕的情况呢?

假设你正在做很多先进的Git Stuff,并且你已经做了一个存储,并且想要git stash apply --index ,但是不能再使用--index来应用保存的存储,因为分支已经发散了自从你保存它以来太多了。

这是git stash branch的用途。

如果你:

  1. 那么当你做原始stash ,检查你的确切提交
  2. 创build一个新的分支,最后
  3. git stash apply --index

重新创build更改的尝试肯定奏效。 这是git stash branch newbranch所做的。 (然后,它成功地应用了,然后它就下降了。)


关于--index一些最后的话(它到底是什么?)

--index做的很简单,但内部有些复杂:

  • 当你有改变时,你必须在commit之前git add (或“阶段”)他们。
  • 因此,当你运行git stash ,你可能已经编辑了foozorg这两个文件,但是只能执行其中的一个。
  • 所以当你要求隐藏的时候,如果它git addadd东西而不是 git add了未添加的东西,那可能会很好。 也就是说,如果你在stash之前add ed foo而不是zorg ,那么完成相同的设置可能会很好。 什么上演,应该再次上演; 什么修改,但不上演,应该再次修改,但不上演。

apply--index标志尝试设置这种方式。 如果你的工作树是干净的,这通常是正常的。 如果你的工作树已经有东西add ,但是,你可以看到这里可能会有一些问题。 如果你没有使用--indexapply操作不会保留整个stage / unstaged的设置。 相反,它只是调用git的合并机制,使用“隐藏包”中的工作树提交。 如果你不关心保持上演/未上架,留下 – --index使得它更容易git stash apply做它的事情。

 git stash pop 

将一切都恢复原状

如注释中所build议的那样,您可以使用git stash branch newbranch将存储应用到新的分支,这与运行相同:

 git checkout -b newbranch git stash pop