强制Git Stash覆盖已添加的文件

356

我有一些在git中未被跟踪的文件。我对它们进行了更改,想要提交这些更改,但是意识到我忘记了先检入未修改的文件。所以我将这些文件藏起来(stash),然后添加了未修改的版本。

然后当我将这个stash应用到仓库时,由于文件已经被添加过了,我会遇到冲突。

我该如何应用这个stash并且强制使用stash里的版本而不是仓库中原来的版本呢?

谢谢


14
暂时的丑陋解决方案:在执行 git stash apply 命令前,使用 git rm 命令移除新添加的文件。这样做可以让你暂存更改,直到有更好的解决方案出现。 - tom
那样不会丢失历史记录吗?添加未修改版本的原因是为了保留历史记录。 - Stefan
1
不会丢失历史记录。如果您将一个文件删除,稍作修改后再添加回去,并提交更改,git 将把它视为一次小修改。 - tom
9个回答

577

使用git checkout代替git stash apply

警告:下面的命令将恢复当前目录(.)中所有文件到其存储版本。如果您有未提交或未暂存的更改,它们将永久丢失

  • 如果在创建存储后编辑了文件,则这些更改将丢失。
  • 如果您只存储了特定文件(使用git stash push <pathspec>...git stash -p),请不要使用此命令,因为所有其他文件中的更改都将丢失

在运行此命令之前,请使用git status检查是否存在未提交或未暂存的更改。

# WARNING: uncommitted/unstaged changes will be permanently lost
$ git checkout stash -- .
$ git commit

如果工作目录中有其他需要保留的文件更改,以下是较轻量级的替代方案:
$ git merge --squash --strategy-option=theirs stash

如果索引有更改,或合并将影响到具有本地更改的文件,则 Git 将拒绝合并。单个文件可以使用以下命令从存储中检出:

$ git checkout stash -- <paths...>

或者通过交互方式

$ git checkout -p stash

4
当我运行git checkout stash -- .这个命令时,它实际上没有做任何事情。 - Rotsiser Mho
3
Git在提供确认信息方面并不是很好。你确定它什么都没做吗?对我来说运行得很好。 - Sinjai
7
我不得不在包含我的更改的最高父文件夹中运行 git checkout stash -- .,否则它只会将更改应用于我运行命令的文件夹。 - Leo
1
@Leo:没错,这是因为“.”指定了当前目录(你可以替换它为其他路径而不是改变目录)。我更新了我的答案以使它更清晰明了。 - tom
1
@tom 比较麻烦的方法。我覆盖了未提交的更改,但幸运的是还有另一种恢复选项:PHPStorm 的本地历史记录拯救了我。 - Szczepan Hołyszewski
显示剩余6条评论

44

git stash show -p | git apply

然后如果您想要删除暂存的文件,使用 git stash drop 命令。


2
注意:为了正确运行,您应该在存储库的根目录中,否则您将会得到这个 - Ruslan
@Ruslan 我在我的存储库根目录中遇到了这个问题。 - Leo
1
如果我收到“补丁不适用”的消息,该怎么办?我只想获取我的存储更改! - eis
3
@eis,你可以将--reject --whitespace=fix作为选项添加到git apply中。查看这个解释了解它的工作原理。 全部命令:git stash show -p | git apply --reject --whitespace=fix - Hassan TBT
@HassanTBT 奇怪的是,这个完全忽略了我存储的一个文件中的更改。它还给我留下了一些.rej文件需要清理。我不得不求助于以下方法:https://dev59.com/1GQn5IYBdhLWcg3wvZN_#76680580 - H.v.M.
@HassanTBT 这样,我得到了"错误:补丁失败"。 - eis

19

要强制执行git stash pop,请运行此命令

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

8
好的回答。但这真是让人沮丧。为什么他们不能只添加一个 --force 标志呢?唉。 - Spongman
这个答案可以通过解释它的功能来改进。 - Ladislav Ondris

5

简述:

git checkout HEAD path/to/file
git stash apply

简化版:

出现这个错误,是因为有未提交的更改需要被覆盖。使用git checkout HEAD命令撤销这些更改。你可以使用git checkout HEAD path/to/file来针对特定文件进行撤销操作。在解决冲突后,可以像往常一样提交更改。


1
你会得到这个错误是因为你想要覆盖未提交的更改。但这并不一定正确。如果你的储藏来自不同的分支,而且你当前的分支和储藏的更改都修改了相同的文件,那么你也会遇到合并冲突。 - tjalling
赞成回滚更改以解决问题的想法。当更改回滚是可管理的时,这尤其有用。 - vpap

2
保留本地源备份,然后强制重置以与GIT存储库对齐。然后更改您的本地代码并提交。

git reset --hard FETCH_HEAD


0

警告:此操作将删除所有未提交的更改。

git checkout HEAD --force
git stash apply

0
在我的情况下,git checkout stash -- 会抛出这个错误。
error: Your local changes to the following files would be overwritten by checkout:
... files ...
Please commit your changes or stash them before you switch branches.
Aborting

解决方法是执行 git checkout stash -- /path/to/each/individual/file

0

我认为Tom的回答中提到的这个选项是自动解决冲突的最简单、最少出错的方法:

$ git merge --squash --strategy-option=theirs stash

你可以像这样输入:git使用stash作为commitish来引用存储的顶部。

它将使您拥有所有存储的文件添加到索引中并解决与存储匹配的问题,但不会创建任何提交。此外,如果您在工作副本中有本地更改,您不会丢失更改,它将中止。

它非常有用,我认为值得在~/.gitconfig中设置别名:

[alias]
    stashforceapply = "!f() { stash=${1:-stash}; git merge --squash --strategy-option=theirs $stash ; }; f"

使用git stashforceapply命令应用最新的存储,或者使用git stashforceapply stash@{1}命令应用下一个存储,以此类推。


0
其他的解决方案对我没有起作用。这是我所做的:
git branch temp && git reset --hard stash && git reset temp && git branch -D temp

硬重置然后重置回更改,可以在不改变分支的情况下修改您的工作树。

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