想要改进这篇文章?提供这个问题的详细答案,包括引文和解释为什么你的答案是正确的。没有足够细节的答案可能会被编辑或删除。
我错误地使用以下命令将文件添加到 Git:
git add myfile.txt
我还没有运行 git commit
。如何撤消此操作,以使这些更改不会包含在提交中?
撤消 git add
用于未提交的更改:
git reset <file>
这将从当前索引(“即将提交”列表)中删除文件,而不更改任何其他内容。
取消暂存所有文件的所有更改:
git reset
在旧版本的 Git 中,上述命令分别相当于 git reset HEAD <file>
和 git reset HEAD
,如果 HEAD
未定义(因为您尚未在存储库中进行任何提交)或不明确(因为您创建一个名为 HEAD
的分支,这是你不应该做的愚蠢的事情)。但是,这个 was changed in Git 1.8.2,因此在现代版本的 Git 中,您甚至可以在进行第一次提交之前使用上述命令:
“git reset”(不带选项或参数)用于在您的历史记录中没有任何提交时出错,但现在它为您提供一个空索引(以匹配您甚至不存在的不存在的提交)。
文档:git reset
你要:
git rm --cached <added_file_to_undo>
推理:
当我是新手时,我第一次尝试
git reset .
(撤消我的整个初始添加),只是为了得到这个(不是那么)有用的信息:
fatal: Failed to resolve 'HEAD' as a valid ref.
事实证明,这是因为 HEAD ref(分支?)直到第一次提交之后才存在。也就是说,如果你的工作流程像我的一样,你会遇到和我一样的初学者问题:
cd 到我伟大的新项目目录来试用 Git,新的热点 git init git add 。 git status ...很多废话滚动... =>该死的,我不想添加所有这些。谷歌“撤消 git add”=> 找到堆栈溢出 - 耶 git reset 。 => 致命:无法将“HEAD”解析为有效参考。
进一步证明,在邮件列表中有 a bug logged 反对这样做的无益。
并且正确的解决方案就在 Git 状态输出中(是的,我掩饰为“废话”)
... # 要提交的更改:# (使用 "git rm --cached
解决方案确实是使用 git rm --cached FILE
。
请注意此处其他地方的警告 - git rm
会删除文件的本地工作副本,但如果您使用 --cached,则不会。这是 git help rm
的结果:
--cached 使用此选项仅从索引中取消暂存和删除路径。工作树文件,无论是否修改,都将被保留。
我继续使用
git rm --cached .
删除所有内容并重新开始。但是没有用,因为虽然 add .
是递归的,但结果是 rm
需要 -r
才能递归。叹。
git rm -r --cached .
好的,现在我回到我开始的地方。下次我将使用 -n
进行试运行,看看会添加什么:
git add -n .
在相信 git help rm
关于 --cached
不会破坏任何东西(如果我拼错了怎么办)之前,我把所有东西都拉到了一个安全的地方。
rm -rf .git
、git init
,因为我不相信 git rm --cached
会保留我的工作副本。它稍微说明了 git 在某些地方仍然过于复杂。 git unstage
应该只是一个标准命令,我不在乎是否可以将其添加为别名。
git reset HEAD <File>...
git add
命令添加了新文件,但不是更改为现有文件。
如果您键入:
git status
Git 会告诉你暂存的内容等,包括如何取消暂存的说明:
use "git reset HEAD <file>..." to unstage
我发现 Git 在推动我在这种情况下做正确的事情方面做得很好。
注意:最近的 Git 版本 (1.8.4.x) 已更改此消息:
(use "git rm --cached <file>..." to unstage)
add
ed 文件(add
仅将新版本保存到缓存中 - 此处将显示您的消息)。在其他地方,如果文件之前没有暂存,它将显示 use "git rm --cached <file>..." to unstage
git reset HEAD <file>
是唯一可以在您想取消暂存文件删除的情况下使用的
git reset HEAD
取消暂存。
git restore --staged <file>
。有关更新,请参阅 my answer below。
澄清一下:git add
将更改从当前工作目录移动到 暂存区(索引)。
这个过程称为分期。因此,用于暂存更改(更改的文件)的最自然命令是显而易见的命令:
git stage
git add
只是 git stage
的一个更易于键入的别名
可惜没有 git unstage
或 git unadd
命令。相关的更难猜测或记住,但很明显:
git reset HEAD --
我们可以很容易地为此创建一个别名:
git config --global alias.unadd 'reset HEAD --'
git config --global alias.unstage 'reset HEAD --'
最后,我们有了新命令:
git add file1
git stage file2
git unadd file2
git unstage file1
我个人使用更短的别名:
git a # For staging
git u # For unstaging
git stage
是 git add
的别名,它是 Git 和其他 SCM 上的历史命令。如果我可以说,它已于 2008 年 12 月在“Git 的 git 存储库”中添加,提交 11920d28da。
除了已接受的答案之外,如果您错误添加的文件很大,您可能会注意到,即使在使用“git reset
”从索引中删除它之后,它似乎仍会占用 .git
目录中的空间。
这没什么好担心的;该文件确实仍在存储库中,但仅作为“松散对象”。它不会被复制到其他存储库(通过克隆、推送),并且空间最终会被回收——尽管可能不会很快。如果你着急,你可以运行:
git gc --prune=now
更新(以下是我试图消除最受好评的答案可能引起的一些混淆):
那么,git add
的真正撤消是什么?
git reset HEAD <file>
?
或者
git rm --cached <file>
?
严格来说,如果我没记错的话:没有。
git add
无法撤消 - 通常是安全的。
让我们首先回顾一下 git add <file>
的实际作用:
如果
鉴于此,这个问题有点模棱两可:
我错误地使用命令添加了文件...
OP 的场景似乎是第一个(未跟踪的文件),我们希望“撤消”从跟踪的项目中删除文件(不仅仅是当前内容)。 如果是这种情况,则可以运行 git rm --cached <file>
。
我们还可以运行 git reset HEAD <file>
。这通常更可取,因为它适用于两种情况:当我们错误地添加了已跟踪项目的版本时,它也会撤消。
但是有两个警告。
首先:(如答案中所指出的)只有一种情况 git reset HEAD
不起作用,但 git rm --cached
起作用:一个新的存储库(无提交)。但是,实际上,这实际上是一个无关紧要的案例。
第二:请注意,git reset HEAD
无法神奇地恢复以前缓存的文件内容,它只是从 HEAD 重新同步它。如果我们误入歧途的 git add
覆盖了之前分阶段的未提交版本,我们将无法恢复它。这就是为什么严格来说,我们无法撤消 [*]。
例子:
$ git init
$ echo "version 1" > file.txt
$ git add file.txt # First add of file.txt
$ git commit -m 'first commit'
$ echo "version 2" > file.txt
$ git add file.txt # Stage (don't commit) "version 2" of file.txt
$ git diff --cached file.txt
-version 1
+version 2
$ echo "version 3" > file.txt
$ git diff file.txt
-version 2
+version 3
$ git add file.txt # Oops we didn't mean this
$ git reset HEAD file.txt # Undo?
$ git diff --cached file.txt # No dif, of course. stage == HEAD
$ git diff file.txt # We have irrevocably lost "version 2"
-version 1
+version 3
当然,如果我们只是遵循通常的懒惰工作流程,只为添加新文件(案例 1)执行“git add”,并且我们通过 commit,git commit -a
命令更新新内容,这并不是很关键。
*(编辑:以上内容实际上是正确的,但仍然有一些稍微有点骇人听闻/令人费解的方法来恢复已暂存但未提交然后被覆盖的更改 - 请参阅 Johannes Matokic 和 iolsmit 的评论)
git cat-file
可用于恢复其内容。
git add
覆盖的更改的另一种方法是通过 git fsck --unreachable
,它将列出所有无法访问的 obj,然后您可以通过 git show SHA-1_ID
或 { 4} 将 >将悬空对象写入 .git/lost-found/commit/
或 .git/lost-found/other/
,具体取决于类型。另见git fsck --help
撤消已添加的文件使用 Git 非常容易。要重置已添加的 myfile.txt
,请使用:
git reset HEAD myfile.txt
解释:
暂存不需要的文件后,要撤消,您可以执行 git reset
。 Head
是本地文件的头部,最后一个参数是文件名。
我在下图中为您创建了更详细的步骤,包括在这些情况下可能发生的所有步骤:
https://i.stack.imgur.com/9JgGD.jpg
git rm --cached . -r
将以递归方式“取消添加”您从当前目录中添加的所有内容
git reset HEAD <file>
会说 fatal: Failed to resolve 'HEAD' as a valid ref.
Git 对每一个可以想象的动作都有命令,但它需要广泛的知识才能把事情做好,因此它充其量是违反直觉的......
你之前做了什么:
更改了文件并使用了 git add . 或 git add
你想要什么:
从索引中删除文件,但保留它的版本并在工作副本中保留未提交的更改: git reset HEAD
将文件从 HEAD 重置为最后一个状态,撤消更改并将它们从索引中删除:# Think `svn revert
从索引和版本控制中删除
从工作副本和版本控制中完全删除
reset head
撤消您当前的更改,但 git 仍在监视该文件。 rm --cached
将文件从版本控制中取出,因此 git 不再检查它的更改(并且还删除最终索引的当前更改,由先前的 add
告知 git),但更改的文件将保留在您的工作副本中,那是在硬盘上的文件夹中。
git reset HEAD <file>
是临时的 - 该命令将仅应用于下一次提交,但 git rm --cached <file>
将取消暂存,直到再次使用 git add <file>
添加它。此外,git rm --cached <file>
意味着如果您将该分支推送到远程,任何拉动该分支的人都会从他们的文件夹中实际删除该文件。
git checkout -- <file>
thanx !
跑
git gui
并手动删除所有文件,或者选择所有文件并单击 unstage from commit 按钮。
git-gui
....” :)
git: 'gui' is not a git command. See 'git --help'.
问题没有明确提出。原因是git add
有两个含义:
将新文件添加到暂存区域,然后使用 git rm --cached file 撤消。将修改后的文件添加到暂存区域,然后使用 git reset HEAD 文件撤消。
如有疑问,请使用
git reset HEAD file
因为它在这两种情况下都做了预期的事情。
警告:如果您对已修改的文件(以前存在于存储库中的文件)执行 git rm --cached file
,则该文件将在 git commit
被删除!它仍然存在于您的文件系统中,但如果其他人拉动您的提交,该文件将从他们的工作树中删除。
git status
会告诉您文件是新文件还是修改:
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: my_new_file.txt
modified: my_modified_file.txt
git rm --cached somefile
的行为是完全错误的。我希望这个答案能够在页面上占据显着位置,从而保护新手免受所有虚假声明的误导。
根据许多其他答案,您可以使用 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 reset filename.txt
将从当前索引中删除一个名为 filename.txt
的文件(也称为“暂存区”,保存“即将提交”的更改),而不更改任何其他内容(工作目录不会被覆盖)。
man git
“重置、恢复和恢复”,据说解释了这 3 个类似的重叠命令(命令的扩散首先表明命令结构不佳),说 git reset “更改提交历史”但这里没有?它还说 git restore “不会更新您的分支”。如果什么都没有改变,那么命令到底在做什么? “分支”实际上是什么意思?在您的评论中,“其他”是什么意思?有时人们会使用假设的上下文并遵循建议可能会受到伤害。
如果您正在进行初始提交并且无法使用 git reset
,只需声明“Git 破产”并删除 .git
文件夹并重新开始
git add -A && git rm --cached EXCLUDEFILE && git commit -m 'awesome commit'
(这也适用于之前没有提交的情况,即 Failed to resolve 'HEAD'
问题)
使用 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”(列表中的第一个条目还原显示)、“返回”以退出还原模式和“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)
$
2019 年更新
正如其他人在相关问题中指出的那样(请参阅 here、here、here、here、here、here 和 here),您现在可以取消暂存单个文件 与:
git restore --staged <file>
并取消暂存所有文件(从 repo 的根目录):
git restore --staged .
笔记
git restore
在 July 2019 中引入并在 2.23 版中发布。
使用 --staged
标志,它可以恢复索引的内容(此处询问的内容)。
使用暂存的未提交文件运行 git status
时,现在是 Git 建议用于取消暂存文件的方法(而不是之前 v2.23 之前的 git reset HEAD <file>
)。
git restore --staged .
与 git reset .
的区别?
当你开始一个新项目时,这里有一种方法可以避免这个令人烦恼的问题:
为您的新项目创建主目录。
运行 git 初始化。
现在创建一个 .gitignore 文件(即使它是空的)。
提交您的 .gitignore 文件。
如果您没有任何提交,Git 会让 git reset
变得非常困难。如果您创建一个很小的初始提交只是为了拥有一个,之后您可以根据需要多次 git add -A
和 git reset
以使一切正常。
此方法的另一个优点是,如果您稍后遇到行尾问题并需要刷新所有文件,这很容易:
检查初始提交。这将删除您的所有文件。
然后再次检查您最近的提交。这将使用您当前的行尾设置检索文件的新副本。
autocrlf
值...这不适用于每个项目,具体取决于设置。
git reset somefile
和 git reset
现在都在进行第一次提交之前工作。自从几个 Git 版本回来后,情况就是如此。
请注意,如果您未能指定修订,则必须包含分隔符。我的控制台中的示例:
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)
git reset <path>
,它没有分隔符就可以正常工作。我也在使用 git 1.9.0。也许它在旧版本中不起作用?
自从您发布问题以来,也许 Git 已经进化了。
$> git --version
git version 1.6.2.1
现在,您可以尝试:
git reset HEAD .
这应该是您正在寻找的。
要从暂存区域中删除新文件(并且仅在新文件的情况下),如上所述:
git rm --cached FILE
仅对意外添加的新文件使用 rm --cached。
--cached
在这里是非常重要的部分。
要重置特定文件夹(及其子文件夹)中的每个文件,可以使用以下命令:
git reset *
git status
来查看剩余的任何内容并手动重置它,即 git reset file
。
使用 *
命令一次处理多个文件:
git reset HEAD *.prj
git reset HEAD *.bmp
git reset HEAD *gdb*
等等
.*
或 .*.prj
,否则 * 通常不会包含点文件或“点目录”
*
不是命令。这是一个通配符。
只需输入 git reset
,它就会恢复,就像您自上次提交以来从未输入过 git add .
。确保你之前已经承诺过。
假设我创建了一个新文件 newFile.txt
:
https://i.stack.imgur.com/nxRgO.png
假设我不小心添加了文件 git add newFile.txt
:
https://i.stack.imgur.com/P6fpa.png
现在我想在提交之前撤消这个添加,git reset newFile.txt
:
https://i.stack.imgur.com/pbbZ8.png
对于特定文件:
git reset my_file.txt git checkout my_file.txt
对于所有添加的文件:
混帐重置。混帐结帐。
注意:checkout 更改文件中的代码并移动到最后更新(提交)状态。重置不会更改代码;它只是重置标题。
git reset <file>
和 git checkout <file>
之间的区别。
要撤消 git add
,请使用:
git reset filename
还有交互模式:
git add -i
选择选项 3 取消添加文件。在我的情况下,我经常想要添加多个文件,并且在交互模式下,您可以使用这样的数字来添加文件。这将占用除 4 之外的所有内容:1、2、3 和 5
要选择一个序列,只需键入 1-5 即可从 1 到 5 全部取值。
此命令将取消隐藏您的更改:
git reset HEAD filename.txt
你也可以使用
git add -p
添加部分文件。
git reset filename.txt
将从当前索引中删除名为 filename.txt 的文件,即“即将提交”区域,而不更改任何其他内容。
git add myfile.txt
# 这会将您的文件添加到待提交列表中
与此命令完全相反的是,
git reset HEAD myfile.txt # This will undo it.
因此,您将处于以前的状态。指定将再次处于未跟踪列表中(以前的状态)。
它将使用该指定文件重置您的头部。所以,如果你的脑袋没有它的意思,它会简单地重置它。
您可以使用 git 命令或 GUI git 取消暂存/撤消。
单个文件
git reset File.txt
多个文件
git reset File1.txt File2.txt File3.txt
https://i.stack.imgur.com/jIpsc.png
git reset src/components/home/Home.js src/components/listItem/ListItem.js src/components/update/Update.js
https://i.stack.imgur.com/8PQ8Y.png
使用 git GUI 的相同示例
git gui
https://i.stack.imgur.com/cE4gI.png
git add
覆盖了之前暂存的未提交版本,我们将无法恢复它。我试图在下面的回答中澄清这一点。git reset HEAD *.ext
其中ext
是您要取消添加的给定扩展名的文件。对我来说是*.bmp
&*.zip
git rm --cached
) 中删除 一个文件,则意味着您正准备提交 删除 该文件。另一方面,git reset HEAD <filename>
会将文件从 HEAD 复制到索引,以便下一次提交不会显示对该文件所做的任何更改。git reset -p
就像git add -p
。这太棒了!git add
个(61/3AF3...
-> 对象 ID613AF3...
),然后是git cat-file -p <object-id>
(恢复几个小时的工作可能是值得的,但也是更频繁地提交的教训......)