如何在Git中放弃未暂存的更改?

6208

我如何抛弃工作副本中未在索引中的更改?


16
git-clean 只会从工作树中删除未被跟踪的文件。详见 https://git-scm.com/docs/git-clean。 - Yega
36
为了澄清Asenar上面的评论,git-clean -df可能会很危险。它会删除本地未被跟踪的文件(例如由.gitignore覆盖的文件)。请仔细阅读以下所有内容,并考虑使用git checkout .代替。 - jacanterbury
26
"git clean -df"警告!我尝试过这个命令,丢失了一些关键文件夹,无法恢复...痛苦! - Gabe Karkanis
72
执行 git status 命令会提供建议,告诉你如何操作!执行 git checkout -- . 命令即可。 - Paulo
28
从2019年7月开始,git status 建议使用 git restore 命令来达到相同的目的,这是一个新的命令。请参考我的2019更新 - prosoitos
显示剩余6条评论
41个回答

7133

使用以下命令对当前工作目录中所有未暂存的文件进行操作:

git restore .

针对特定文件使用:

git restore path/to/file/to/revert
git switch 取代了混淆的 git checkout(详情请参见这里),因此取消了参数歧义。

如果一个文件既有暂存的更改又有未暂存的更改,则只有在 git diff 中显示的未暂存更改被还原。在 git diff --staged 中显示的更改保持不变。

Git 2.23之前

对于当前工作目录中的所有未暂存文件:

git checkout -- .

针对特定文件:

git checkout -- path/to/file/to/revert

-- 用于消除歧义(这被称为参数消歧义)。


150
这似乎是 Git 的标准做法,也就是如果你输入“git status”,Git 会告诉你要做什么。 - ABMagil
39
如果存在未跟踪的文件,此方法无法使用。Git会提示错误信息:“error: The following untracked working tree files would be overwritten by checkout: ...”。请先处理这些未跟踪的文件再执行操作。 - Michael Iles
114
这个问题是新手问题,"git checkout -- ." 语句在语义上是什么意思? - kaid
135
git checkout -- .的意思和git checkout .一样,只是你明确表示你没有指定分支名称。它们都表示在当前分支上检出'.'或'./'的HEAD版本。如果你通常执行git checkout branch-name directory-or-file-name,它会获取branch-name分支中directory-or-file-name的HEAD版本。 - akgill
28
这个变体并不完美,因为它无法处理这样一种情况:当你的修改后的代码库在清除更改时不在HEAD修订版上,并且你不想将其更新到HEAD版本,而只想清除修改。 - alexykot
显示剩余28条评论

3135

另一种更快的方法是:

git stash save --keep-index --include-untracked

如果您不想彻底处理它,可以不包括--include-untracked

之后,您可以使用git stash drop命令删除该存储(stash)。


13
这个问题特别询问的是没有在索引中的更改。git reset命令也会丢弃索引中的更改。 - Greg Hewgill
173
git checkout -- . 是更快的方法。 - Frank
44
无论是 git stash 还是任何类型的 git checkout 都不会丢弃未暂存的删除操作。根据 git status 的输出,实际正确的方法是使用某种形式的 git reset HEAD - Chris Warth
154
这会污染储藏堆栈。git checkout -- . 只需一个命令就可以完成任务。 - Felipe Tonello
3
@FelipeTonello 我希望我能给你100声望分作为对你评论的回报。在我的测试中,它看起来确实做到了我想要的。相反,我花了最后一小时使用“git checkout --*”来解决所有未被跟踪的文件错误。 - Buttle Butkus
显示剩余16条评论

2278

看起来完整的解决方案是:

git clean -df
git checkout -- .

警告:尽管它不会删除在.gitignore中直接提到的被忽略文件,git clean -df 可能会删除位于文件夹中的被忽略文件

git clean可以移除所有未跟踪的文件,而git checkout则可以清除所有未提交的更改。


158
另外两个答案实际上不起作用,而这一个起了作用。 - John Hunt
20
@dval 这是因为第一个命令删除了未索引的文件,第二个命令删除了未暂存的更改(已索引的文件)。因此,如果您没有任何已暂存的更改,则与使用 git reset --hard 恢复到上一个提交相同。 - Amanuel Nega
95
小心运行 git clean -df 命令。如果您不理解它的作用,可能会意外删除您想要保留的文件,例如 robots.txt、已上传的文件等。请谨慎操作。 - ctlockey
46
正如@ctlockey所说,第一个命令如果目录仅由被忽略的文件组成,则也会删除目录... 我在项目中失去了大量配置文件 :( 请注意。 - Maxime Lorant
3
啊!我刚才用 git clean -df 命令删除了我的项目文件夹?怎么办才能找回来?求救!!!我已经做了 ls 命令,但是看不到我没有意图删除的另一个文件夹。 - user2441441
显示剩余20条评论

402

此命令将检查当前目录的当前索引,丢弃所有从当前目录向下的文件中的更改。

git checkout .

或者使用这个命令从索引中检出所有文件,覆盖工作树中的文件。

git checkout-index -a -f

22
这是正确答案,因为它正确地处理了一些文件同时具有暂存和未暂存更改的情况。请注意,此解决方案会丢弃未暂存的更改;如果您希望保留这些更改,则应使用@greg-hewgill的答案,即 git stash save --keep-index - Rhubbarb
如果你只有一个分支,git checkout -- 将无法工作。而 git checkout . 则总是有效的。 - Ed Bayiates
非常感谢!终于有一个始终有效的答案了!这可以与 git clean 结合使用,还可以删除未跟踪的文件。 - jlh
不是开玩笑,但这似乎是唯一有效的答案。评分较高的答案似乎什么也没做。我相信它们会做些什么,但它们肯定不会“重置”未暂存的更改。 - FreelanceConsultant

304
git clean -df

从当前目录开始,通过递归删除未受版本控制的文件来清理工作区。

-d:除了未跟踪的文件,还会删除未跟踪的目录

-f:强制删除(根据 clean.requireForce 设置可能不必要)

运行git help clean查看手册。


为什么这个答案没有所有的投票?它在2011年就被回答了,但仍然是正确的。 - Eugene Braginets
这应该是被接受的答案。 - zwcloud
这应该被接受。运行git help时,git显示的定义明确表示:“从工作树中删除未跟踪的文件”这正是OP所问的。 - fjplaurr

214

2019更新

您现在可以使用以下命令丢弃一个已跟踪文件中的未暂存更改:

git restore <file>

在当前目录中(递归地),以及所有被跟踪的文件中,使用以下内容:

git restore .

如果你在仓库的根目录下运行后者,它将放弃项目中所有已跟踪文件中未暂存的更改。
注:
- `git restore` 是在2019年7月引入的,并作为将 `git checkout` 命令拆分为文件的 `git restore` 和分支的 `git switch` 的一部分,在版本2.23中发布。 - `git checkout` 仍然像以前一样工作,旧答案仍然完全有效。 - 在工作树中有未暂存更改时运行 `git status`,这是 Git 建议使用的方法来放弃它们(而不是在 v2.23 之前使用的 `git checkout -- `)。 - 与 `git checkout -- .` 一样,这只会放弃已跟踪文件中的更改。因此,Mariusz Nowak的答案仍然适用,如果您想放弃包括未跟踪文件在内的所有未暂存更改,则可以像他建议的那样运行额外的 `git clean -df` 命令。

3
我想撤销我的未提交更改,但不影响新添加的文件,因此 git restore . 完美地解决了这个问题。谢谢。 - Saurabh Misra
4
我运行了 git restore <文件名> 命令,它完美地执行了。 - Merlin
2
根据man页面的描述,git restore . 仅恢复当前目录中的所有文件,而不是整个代码库中的所有文件。 - jarno
3
你是对的。谢谢!我刚刚测试了一下,确实是这样的。不过,它是递归的。所以当从项目根目录运行时,它会应用于整个仓库。我会编辑我的回答。 - prosoitos
1
谢谢!这真是改变生活的一刻。以前我总是在做 git commit -m "wip" && git reset --hard && git reset --soft HEAD~1 && git reset - gomes
显示剩余6条评论

129

我最喜欢的是

git checkout -p

这可以让你有选择性地还原段落。

另请参见:

git add -p

14
我喜欢在丢弃之前看到实际的变化能力。 - Penghe Geng
这是我使用的。git checkout -p 然后输入"a"以接受所有内容。 - Mattis
3
我从未考虑过,-p 参数可以添加额外的安全层。结合 git clean -d 命令来回答 OP 的问题。 - Stephan Henningsen

126

由于没有答案提供我所使用的确切选项组合,因此在这里:

git clean -dxn .  # dry-run to inspect the list of files-to-be-removed
git clean -dxf .  # REMOVE ignored/untracked files (in the current directory)
git checkout -- . # ERASE changes in tracked files (in the current directory)

这是用于git clean选项的在线帮助文本:

-d

除了未跟踪的文件外,还会删除未跟踪的目录。如果未跟踪的目录由不同的Git存储库管理,则默认情况下不会将其删除。如果您真的想删除此类目录,请将选项-f使用两次。

-x

不使用从.gitignore(按目录)和$GIT_DIR/info/exclude读取的标准忽略规则,但仍然使用通过-e选项给定的忽略规则。这允许删除所有未跟踪的文件,包括构建产品。可以使用此方法(可能与git reset一起)创建原始的工作目录以测试干净的构建。

-n

实际上不会删除任何内容,只显示将要执行的操作。

-f

如果Git配置变量clean.requireForce没有设置为false,则Git clean将拒绝删除文件或目录,除非给出-f-n-i。Git将拒绝删除.git子目录或文件中的目录,除非给出第二个-f


关于您提到的“git checkout .需要在存储库的根目录中完成”的评论,也许您可以提到我们可以使用git reset --hard代替?(实际上等同于git reset --hard HEAD,并且应该适用于当前目录...) - ErikMD
2
关于第一个命令 git clean -dfx,这里有一个提示,我在运行它之前使用的是为了保险起见:只需先运行 git clean -d -x -n,以显示要删除的文件列表,然后通过运行 git clean -d -x -f 来确认操作(我将参数 -n-f 放在末尾,以便能够在终端中快速更改它)。 - ErikMD
6
快速提醒,这是不可逆的操作,如果你有在.gitignore中的文件,它们将会丢失。因此,在执行此操作前请考虑备份您的项目。 - Rob
@MartinG 我刚好趁机加入了我的两个建议,包括添加“dry-run”步骤的一个建议(因为安全第一!)。无论如何,如果需要的话,请随意修改我的编辑! - ErikMD
1
如何删除在 git status 中显示的未跟踪文件,而不删除在 .gitignore 中的未跟踪文件? - Aaron Franke

84

如果你只是希望撤销对现有文件的更改,请使用checkout在这里有文档记录)。

git checkout -- .
  • 没有指定分支,所以它会检出当前分支。
  • 双破折号 (--) 告诉 Git 其后应被作为第二个参数(路径)处理,你省略了分支的指定。
  • 句点 (.) 表示所有路径。

如果您想要删除自上次提交以来添加的文件,请使用 clean在此文档中有说明):

git clean -i 
  • -i选项启动交互式的clean,以防止误删。
  • 还有一些其他选项可用于更快地执行;请参阅文档。

如果您希望将更改移动到保留空间以供稍后访问,请使用stash在此处记录):

git stash
  • 所有更改都将被移到 Git 的存储区(Stash)中,以备以后可能需要访问。
  • 有几个选项可用于更加细致的暂存;请参阅文档。

这将完全转换您的更改并丢弃前一个提交中新添加的文件。 - Yohan Chung
它会删除新添加的文件吗?还是只会撤销旧的未暂存文件中的更改? - KawaiKx

68

23
我来这里两次,读了这个答案,却忘了结尾的句号 .。提醒未来的自己:这个句号是必须的 - bejado
3
我需要在一个子目录中摆脱所有本地更改,而不会影响其他任何更改。这个答案非常有帮助,谢谢。 - Ally
2
请描述这两个命令的作用。没有解释真的没有帮助。 - Chris Kennedy
2
优秀。checkout 命令一次完成了最流行的命令需要两次才能完成的操作。还可以跟进 git clean -fd 命令来清理不在索引中的文件。 - oligofren

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