如何在提交前撤销 'git add'?

11227

我错误地使用以下命令将文件添加到Git:

git add myfile.txt

我还没有运行git commit命令。我该如何撤销这个操作,以便这些更改不会被提交?


50
从 Git v1.8.4 开始,所有使用 HEADhead 的答案现在可以使用 @ 代替 HEAD。请参见此答案(最后一节)了解为什么可以这样做。 - user456814
5
我做了一个小总结,展示了取消暂存文件的所有方法:https://dev59.com/Dmw05IYBdhLWcg3w9mhW#16044987 - Daniel Alder
8
如果您使用Eclipse,取消勾选提交对话框中的文件就像简单的操作一样。 - Hamzahfrq
2
这是一份来自Github的绝佳资源:如何使用Git撤销(几乎)所有操作 - jasonleonhard
3
在发布新答案之前,请考虑此问题已经有25个以上的答案。确保您的答案提供了现有答案中不存在的内容。 - Sazzad Hissain Khan
显示剩余6条评论
39个回答

96
根据其他回答,您可以使用git reset。但是,我找到了一篇非常好的文章,实际上为git unadd添加了Git命令(别名):请参见git unadd了解详细信息或者..简单地说,
git config --global alias.unadd "reset HEAD"

现在你可以

git unadd foo.txt bar.txt

或者 / 直接:

git reset HEAD foo.txt bar.txt

我如何在提交之前撤销git add操作?你只需要使用 git unadd 命令。这是正确的答案。 - gndps

80
git reset filename.txt

将从当前索引(也称为“暂存区”,其中保存了即将提交的更改)中删除名为filename.txt的文件,而不改变其他任何内容(工作目录不会被覆盖)。


一些 Git 文档存在错误,术语不一致且含糊不清。man git 中的“Reset, restore and revert”解释了这三个类似且重叠的命令(命令的过多表明首先命令结构不佳),说 git reset “更改提交历史记录”,但在这里却没有?它还说 git restore “不会更新您的分支”。如果没有任何更改,那么这个命令到底是在做什么?“分支”实际上是什么意思?在您的评论中,“anything else”是什么意思?有时人们使用假定的上下文,并遵循建议可能会造成损失。 - NeilG

75

如果您的代码库是初始提交(即没有任何提交记录),无法使用 git reset,那么可以考虑宣布"Git破产"并删除 .git 文件夹,然后重新开始。


6
一个提示是,在删除文件夹之前,复制你的 .git/config 文件,如果你已经添加了远程仓库地址。 - Tiago
5
@ChrisJohnsen的评论言简意赅。有时候,您想提交除某个文件之外的所有文件:git add -A && git rm --cached EXCLUDEFILE && git commit -m 'awesome commit'(当没有先前的提交时,也适用,关于“无法解析'HEAD'”的问题)。 - user246672

73

2019更新

正如其他相关问题中所指出的(请参见这里这里这里这里这里这里这里),您现在可以使用以下命令取消暂存单个文件

git restore --staged <file>

使用以下命令取消暂存所有文件(从存储库的根目录开始):

git restore --staged .

笔记

git restore是在2019年7月引入的,并在2.23版本中发布。
使用--staged标志,它将恢复索引的内容(这就是本文所要求的内容)。

当使用已暂存但未提交的文件运行git status时,Git现在建议使用它来取消暂存文件(而不是在v2.23之前使用的git reset HEAD <file>)。


感谢您提供更新的答案。您能详细说明 git restore --staged .git reset . 有何不同吗? - Dan Dascalescu
这个帖子是否回答了你的问题,@DanDascalescu? - prosoitos

64
你可以使用git命令或GUI Git来取消暂存或撤销更改。 单个文件
git reset File.txt

多个文件

git reset File1.txt File2.txt File3.txt

例子

假设您错误地添加了Home.jsListItem.jsUpdate.js,

输入图像描述

并希望撤消/重置 =>

git reset src/components/home/Home.js src/components/listItem/ListItem.js src/components/update/Update.js

这里输入图片描述

使用Git GUI的相同示例。

git gui

打开一个窗口。取消选中您的文件,从已暂存的更改(将提交)中移除。

在此输入图片描述


如果您决定回答一个已经有成熟且正确答案的老问题,那么在后期添加新答案可能不会为您带来任何信誉。如果您有一些独特的新信息,或者您确信其他答案都是错误的,请务必添加新答案,但是“又一个答案”在问题提出很久以后给出相同基本信息通常不会为您赢得太多信誉。您添加了“漂亮的图片” - 我并不认为它们都有益。如果我正在使用手机阅读此答案,它们将是难以阅读的。 - Jonathan Leffler
2
我喜欢你的截图在向你大喊,告诉你应该使用git restore --staged <file>...而不是你提供的解决方案XD - Kim

54

使用 git add -i 命令,从即将提交的内容中移除刚添加的文件。例如:

意外添加了某个文件:

$ git add foo
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   foo
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
# [...]#

进入交互式添加以撤销您的添加(在这里键入的git命令是“r”(恢复),“1”(revert显示的第一个条目),'return'退出撤销模式,和“q”(退出)):

$ git add -i
           staged     unstaged path
  1:        +1/-0      nothing foo

*** Commands ***
  1: [s]tatus     2: [u]pdate     3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff       7: [q]uit       8: [h]elp
What now> r
           staged     unstaged path
  1:        +1/-0      nothing [f]oo
Revert>> 1
           staged     unstaged path
* 1:        +1/-0      nothing [f]oo
Revert>> 
note: foo is untracked now.
reverted one path

*** Commands ***
  1: [s]tatus     2: [u]pdate     3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff       7: [q]uit       8: [h]elp
What now> q
Bye.
$

就是这样!以下是您的证明,显示“foo”已经回到未跟踪的列表中:

$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
# [...]
#       foo
nothing added to commit but untracked files present (use "git add" to track)
$

46

以下是在启动新项目时避免问题的方法:

  • 创建新项目的主目录。
  • 运行git init命令。
  • 现在创建一个.gitignore文件(即使它是空的)。
  • 提交您的.gitignore文件。

如果您没有任何提交记录,Git会让使用git reset变得非常困难。为了有一个提交记录,您可以创建一个微小的初始提交,并在此之后可以使用git add -Agit reset多次进行更改以达到正确性。

这种方法的另一个优点是,如果以后遇到行结尾问题并需要刷新所有文件,这很容易:

  • 检出初始提交。 这将删除所有文件。
  • 然后重新检出您最近的提交。 这将使用当前的行结尾设置检索文件的最新副本。

1
确认!在执行了git add .之后,git报错说HEAD损坏。按照您的建议,我可以轻松地进行git add和reset操作,没有任何问题 :) - Kounavi
1
第二部分能够正常运行,但有点笨拙。行尾的处理方式取决于 autocrlf 值... 这种方法不适用于所有项目,具体取决于设置。 - sjas
1
这个答案在发布时是合理的,但现在已经过时了;在进行第一次提交之前,git reset somefilegit reset 都是有效的。自几个 Git 版本以来就是这种情况。 - Mark Amery

44

请注意,如果您未指定修订版本,则必须包含分隔符。以下是我控制台中的示例:

git reset <path_to_file>
fatal: ambiguous argument '<path_to_file>': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions

git reset -- <path_to_file>
Unstaged changes after reset:
M    <path_to_file>

(Git版本1.7.5.4)


2
我尝试了 git reset <path>,没有分隔符也可以正常工作。我还在使用 git 1.9.0 版本。也许在旧版本中无法正常工作? - user456814

43

也许自您发布这个问题以来,Git已经发生了变化。

$> git --version
git version 1.6.2.1

现在,您可以尝试:

git reset HEAD .
这应该是你要找的内容。

2
当然可以,但是接下来你会有一个问题,那就是如何取消添加两个(或更多)文件中的一个。不过,“git reset”手册确实提到了“git reset <paths>”是“git add <paths>”的相反操作。 - Alex North-Keys

39
要从暂存区中删除新文件(仅限于新文件的情况),如上所建议:
git rm --cached FILE

只有在意外添加新文件时才使用rm --cached。


4
请注意,“--cached”在这里是非常重要的一部分。 - takeshin
1
-1;不,这并不是取消暂存文件,而是将文件标记为已删除(但实际上并未从您的工作树中删除)。 - Mark Amery

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