我有一堆临时的和非临时的更改,我想快速切换到另一个分支,然后切换回来。
因此,我使用以下工具来暂存我的更改:
$ git stash push -a
(In事后看来,我可能本可以使用--include-untracked
而不是--all
)
然后,当我去弹出藏匿我得到了一大堆错误沿着:
$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry
似乎没有任何变化恢复从藏匿。
我还尝试了$ git stash branch temp
,但显示了相同的错误。
我确实找到了一个解决办法,那就是用途:
$ git stash show -p | git apply
灾难暂时避免了,但这引发了一些问题。
为什么这个错误会在第一时间发生,我如何避免它的下一次?
8条答案
按热度按时间sxpgvts31#
我设法重新创建了您的问题。似乎如果您隐藏未跟踪的文件,然后创建这些文件(在您的示例中,
foo.txt
和bar.txt
),那么您对未跟踪文件的本地更改将在您应用git stash pop
时被覆盖。要解决此问题,您可以使用以下命令。这将覆盖任何未保存的本地更改,因此要小心。
Here is some further information I found on the previous command .
oalqel3c2#
作为一点额外的解释,请注意
git stash
可以提交两次,也可以提交三次。如果您使用--all
或--include-untracked
选项的任何拼写,则会得到三个。这两个或三个提交在一个重要方面是特别的:它们位于 no 分支上。Git通过特殊的名称
stash
来定位它们。1然而,最重要的是Git允许你--以及 * 使 * 你--对这两个或三个提交做什么。为了理解这一点,我们需要看看这些提交中有什么。藏起来的东西
每个提交可以列出一个或多个 parent 提交。它们形成了一个图,其中稍后的提交指向较早的提交。stash通常保存两个提交,我喜欢称之为
i
(索引/暂存区内容)和w
(工作树内容)。还请记住,每个提交保存一个快照。在正常提交中,这个快照是从索引/暂存区的内容中创建的,所以i
提交实际上是一个非常正常的提交!它只是不在任何分支上:如果您正在创建一个普通的藏匿点,那么
git stash
代码现在通过复制所有跟踪的工作树文件来创建w
Git将这个w
提交的第一个父提交设置为指向HEAD
提交,第二个父提交设置为指向i
提交。它将stash
设置为指向该w
提交:如果添加
--include-untracked
或--all
,Git会在i
和w
之间额外提交一次u
。u
的快照内容是那些未被跟踪但未被忽略的文件(--include-untracked
),或未跟踪的文件,即使它们被忽略(--all
).这个额外的u
提交 * 没有 * 父提交,然后当git stash
生成w
时,它将w
的 * 第三 * 父提交设置为这个u
提交,从而得到:此时,Git还会 * 移除 * 任何在
u
提交中结束的工作树文件(使用git clean
来执行此操作)。恢复藏匿
当你去 restore 一个存储时,你可以选择使用
--index
,或者不使用它。这告诉git stash apply
(或者任何内部使用apply
的命令,比如pop
)它应该 * 使用 *i
提交来尝试修改你的当前索引。(more或者更少;这里有一堆琐碎的细节妨碍了基本思想)。
如果省略
--index
,git stash apply
将完全忽略i
提交。如果stash只有两次提交,
git stash apply
现在可以应用w
提交。(不允许提交或将结果视为正常合并),使用在其上进行隐藏的原始提交(i
的父级,以及w
的第一个父级)作为合并基,w
作为--theirs
提交,并且您的当前(HEAD)commit作为合并的目标。如果合并成功,那么一切都很好-至少 Git 是这么认为的-并且git stash apply
本身也成功了。如果使用git stash pop
来应用stash,如果合并失败,Git会声明apply失败。如果使用的是git stash pop
,代码会保留stash,并显示与git stash apply
相同的失败状态。但如果你有第三次提交--如果你正在应用的缓存中有一个
u
提交--那么事情就改变了!**没有办法假装u
提交不存在。**4 Git坚持将所有来自u
提交的文件提取到当前的工作树中。这意味着这些文件要么根本不存在,或者具有与X1 M51 N1 X提交中相同的内容。要实现这一点,您可以自己使用
git clean
-但请记住,未跟踪的文件(不管是否忽略)在Git仓库中没有其他存在,所以要确保这些文件都可以被销毁!或者,你可以创建一个临时目录,并将文件移到那里进行安全保存-或者甚至再做一个git stash save -u
或git stash save -a
,因为这些将为您运行git clean
。但这只是留给您另一个u
风格的隐藏要稍后处理。1这实际上是
refs/stash
。如果你创建一个名为stash
的分支,这一点很重要:分支的全名是refs/heads/stash
,所以它们不冲突。但是不要这样做:Git 不会介意,但你会把自己搞糊涂。:-)2
git stash
代码实际上直接使用了git merge-recursive
,这是有必要的,因为有很多原因,而且还有一个副作用,那就是要确保Git在你解决冲突和提交时不会将其视为合并。3这就是为什么我建议避免使用
git stash pop
,而使用git stash apply
。你有机会检查应用了什么,并决定它是否 * 实际上 * 应用正确。如果没有,你 * 仍然有你的隐藏 * 这意味着你可以使用git stash branch
来完美地恢复所有内容。好吧,假设没有讨厌的u
提交。4确实应该:
git stash apply --skip-untracked
之类的。还应该有一个变体,意思是 * 把所有那些u
提交文件放到一个新目录 *,例如,git stash apply --untracked-into <dir>
。ru9i0ody3#
要在Daniel Smith's answer上展开:该代码仅恢复跟踪的文件,即使您在创建隐藏时使用了
--include-untracked
(或-u
)。这将完全恢复跟踪的内容(在
stash
中)和未跟踪的内容(在stash^3
中),然后删除隐藏内容。*小心-这将覆盖所有与您的藏匿内容!
git checkout
恢复文件会导致它们全部自动转移,因此我添加了git reset
来取消转移所有内容。stash@{0}
和stash@{0}^3
,在我的测试中,使用或不使用@{0}
都是一样的资料来源:
stash^3
提交的信息)4uqofj5v4#
除了别的答案外,我还耍了个小花招
*已删除所有新文件(已存在的文件,例如问题中的foo.txt和bar.txt)
git stash apply
(可以使用任何命令,例如应用、弹出等)wljmcqd85#
解决此问题的一个简单方法是将现有冲突文件重命名为不冲突文件。
例如,如果运行
git stash apply/pop
并获得:尝试将
foo.md
重命名为foo.new.md
,然后重新运行git stash apply/pop
,这次不会出现错误,并且foo.md
和foo.new.md
都可供您使用。kokeuurv6#
我刚刚遇到了这个问题。由于上面的答案不工作,而不丢失文件从藏匿,我即兴。
我用
git stash -u
创建的stash没有跟踪新添加的文件。其中一些文件来自代码生成,在我尝试弹出stash之前被单独提交到master分支。当我弹出stash时,我得到了以下内容:根据git无法合并两个不同的新文件的理论,我删除了工作目录中的每一个指定文件,然后就可以应用完整的隐藏文件,而不会丢失文件或出现错误。
sxpgvts37#
以下是我为使其发挥作用而采取的步骤:
1.我删除了工作目录中邮件中提到的每个文件。
1.我重新申请了未设置的藏匿地点。
应该应用隐藏中的所有文件,没有任何错误。
bejyjqdl8#
一旦你把你的分支命名为(本地分支)与你的本地更改。让我们假设文件A,文件B和新添加的文件C。文件C是在untrack阶段,而把代码藏在你的分支。
稍后,如果你使用git pull来获取master文件中的最新代码,文件A被更新了。之后,你尝试在分支中应用stash,但它不会给予未跟踪的文件,例如文件C,因为在进行pull请求时,文件A被更新了。这是新版本GIT的一个限制。
变通方法或解决方案:将你的本地分支头指向文件A没有更新的地方,并应用stash代码,现在你可以控制所有三个文件,将untrack转换为track文件,或者复制一份适合你的文件。用git pull命令更新你的分支头,你也有了自己的代码(可以从stash获取,或者如果你复制了,可以手动粘贴)