繁体   English   中英

如何在提交之前撤消“git add”?

How do I undo 'git add' before commit?

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

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

git add myfile.txt

我还没有运行git commit 如何撤消此操作以使这些更改不会包含在提交中?

38 个回复

使用以下命令撤消git add未提交的更改:

git reset <file>

这将从当前索引(“即将提交”列表)中删除文件,而不更改任何其他内容。


取消暂存所有文件的所有更改:

git reset

在旧版本的 Git 中,上述命令分别相当于git reset HEAD <file>git reset HEAD ,如果HEAD未定义(因为您尚未在存储库中进行任何提交)或不明确(因为您创建了一个名为HEAD的分支,这是你不应该做的愚蠢的事情)。 不过,这在 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(分支?)直到第一次提交之后才存在。 也就是说,如果你的工作流程像我的一样,你会遇到和我一样的初学者问题:

  1. cd 到我伟大的新项目目录来试用 Git,新的热点
  2. git init
  3. git add .
  4. git status

    ...很多废话卷轴...

    =>该死的,我不想添加所有这些。

  5. 谷歌“撤消 git 添加”

    => 找到堆栈溢出 - 耶

  6. git reset .

    => 致命:无法将“HEAD”解析为有效参考。

进一步证明,在邮件列表中 记录了一个针对此无用的错误

并且正确的解决方案就在 Git 状态输出中(是的,我掩饰为“废话”)

 ... # Changes to be committed: # (use "git rm --cached <file>..." to unstage) ...

解决方案确实是使用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不会破坏任何东西(如果我拼写错误怎么办)之前,我把所有东西都压缩到了一个安全的地方。

如果您键入:

git status

Git 会告诉你暂存的内容等,包括如何取消暂存的说明:

use "git reset HEAD <file>..." to unstage

我发现 Git 在推动我在这种情况下做正确的事情方面做得很好。

注意:最近的 Git 版本 (1.8.4.x) 已更改此消息:

(use "git rm --cached <file>..." to unstage)

澄清一下: git add将更改从当前工作目录移动到暂存区域(索引)。

这个过程称为staging 因此,用于暂存更改(更改的文件)的最自然命令是显而易见的命令:

git stage

git add只是git stage的一个更易于键入的别名

可惜没有git unstage 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 reset ”从索引中删除它,它似乎仍然占据.git目录中的空间。

这没什么好担心的; 该文件确实仍在存储库中,但仅作为“松散对象”。 它不会被复制到其他存储库(通过克隆、推送),并且空间最终会被回收——尽管可能不会很快。 如果你着急,你可以运行:

git gc --prune=now

更新(以下是我试图消除最受好评的答案可能引起的一些混淆):

那么,哪个是git add的真正撤消

git reset HEAD <file>

或者

git rm --cached <file>

严格来说,如果我没记错的话: none

git add无法撤消- 通常是安全的。

让我们首先回顾一下git add <file>的实际作用:

  1. 如果<file>之前没有被跟踪过git add会将它和它的当前内容一起添加到缓存中。

  2. 如果<file>已被跟踪git add将当前内容(快照、版本)保存到缓存中。 在 Git 中,这个动作仍然被称为add ,(不仅仅是更新它),因为一个文件的两个不同版本(快照)被视为两个不同的项目:因此,我们确实是在缓存中添加一个新项目,最终后来承诺。

鉴于此,这个问题有点模棱两可:

我错误地使用命令添加了文件...

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

当然,如果我们只是遵循通常的惰性工作流程,只为添加新文件执行“git add”(案例 1),并且我们通过提交git commit -a命令更新新内容,这并不是很关键。


*(编辑:以上内容实际上是正确的,但仍然可能有一些稍微骇人听闻/复杂的方法来恢复已上演但未提交然后被覆盖的更改 - 请参阅 Johannes Matokic 和 iolsmit 的评论)

使用 Git撤消已添加的文件非常容易。 要重置已添加的myfile.txt ,请使用:

git reset HEAD myfile.txt

解释:

暂存不需要的文件后,要撤消,您可以执行git reset Head是本地文件的头部,最后一个参数是文件的名称。

我在下图中为您创建了更详细的步骤,包括在这些情况下可能发生的所有步骤:

git重置头文件

git rm --cached . -r

将以递归方式“取消添加”您从当前目录中添加的所有内容

Git 对每一个可以想象的动作都有命令,但它需要广泛的知识才能把事情做好,因此它充其量是违反直觉的......

你之前做了什么:

  • 更改了一个文件并使用了git add . ,或git add <file>

你想要什么:

  • 从索引中删除文件,但保留它的版本并在工作副本中保留未提交的更改:

     git reset HEAD <file>
  • 将文件从 HEAD 重置为最后一个状态,撤消更改并将它们从索引中删除:

     # Think `svn revert <file>` IIRC. git reset HEAD <file> git checkout <file> # If you have a `<branch>` named like `<file>`, use: git checkout -- <file>

    这是必需的,因为git reset --hard HEAD不适用于单个文件。

  • 从索引和版本控制中删除<file> ,保留未版本控制的文件与工作副本中的更改:

     git rm --cached <file>
  • 从工作副本和版本控制中完全删除<file>

     git rm <file>

问题没有明确提出。 原因是git add有两个含义:

  1. 新文件添加到暂存区域,然后使用git rm --cached file撤消。
  2. 修改后的文件添加到暂存区,然后使用git reset HEAD file撤消。

如有疑问,请使用

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 gui

并手动删除所有文件,或者选择所有文件并单击unstage from commit按钮。

根据许多其他答案,您可以使用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的文件(也称为“暂存区”,保存“即将提交”的更改),而不更改任何其他内容(工作目录不会被覆盖)。

如果您正在进行初始提交并且无法使用git reset ,只需声明“Git 破产”并删除.git文件夹并重新开始

使用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 年更新

正如其他人在相关问题中指出的那样(请参阅此处此处此处此处此处此处此处),您现在可以使用以下命令取消暂存单个文件

git restore --staged <file>

取消暂存所有文件(从 repo 的根目录):

git restore --staged .

笔记

git restore2019 年 7 月推出,并在 2.23 版本中发布。
使用--staged标志,它恢复索引的内容(这里问的是什么)。

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

当你开始一个新项目时,这里有一种方法可以避免这个令人烦恼的问题:

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

如果您没有任何提交,Git 会让执行git reset变得非常困难。 如果您创建一个很小的初始提交只是为了拥有一个,那么您可以根据需要多次git add -Agit reset以使一切正常。

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

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

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

git add myfile.txt

我还没有运行git commit 有没有一种方法可以撤消此操作,因此这些文件将不会包含在提交中?

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

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 已经进化了。

$> git --version
git version 1.6.2.1

现在,您可以尝试:

git reset HEAD .

这应该是您正在寻找的。

要从暂存区域中删除新文件(并且仅在新文件的情况下),如上所述:

git rm --cached FILE

仅对意外添加的新文件使用 rm --cached。

要重置特定文件夹(及其子文件夹)中的每个文件,可以使用以下命令:

git reset *

使用*命令一次处理多个文件:

git reset HEAD *.prj
git reset HEAD *.bmp
git reset HEAD *gdb*

等等

只需输入git reset它就会恢复,就像你从未输入过git add . 自您上次提交以来。 确保你之前已经承诺过。

假设我创建了一个新文件newFile.txt

在此处输入图像描述

假设我不小心添加了文件, git add newFile.txt

在此处输入图像描述

现在我想撤消这个添加,在提交之前, git reset newFile.txt

在此处输入图像描述

对于特定文件:

  • git 重置 my_file.txt
  • git checkout my_file.txt

对于所有添加的文件:

  • 混帐重置。
  • 混帐结帐。

注意: checkout更改文件中的代码并移动到最后更新(提交)状态。 重置不会更改代码; 它只是重置标题。

要撤消git add ,请使用:

git reset filename

还有交互模式:

git add -i

选择选项 3 取消添加文件。 在我的情况下,我经常想要添加多个文件,并且在交互模式下,您可以使用这样的数字来添加文件。 这将占用除 4 之外的所有内容:1、2、3 和 5

要选择一个序列,只需键入 1-5 即可从 1 到 5 全部取值。

Git 暂存文件

此命令将取消隐藏您的更改:

git reset HEAD filename.txt

你也可以使用

git add -p 

添加部分文件。

git add myfile.txt # 这会将你的文件添加到待提交列表中

与此命令完全相反的是,

git reset HEAD myfile.txt  # This will undo it.

因此,您将处于以前的状态。 指定将再次处于未跟踪列表中(以前的状态)。

它将使用该指定文件重置您的头部。 所以,如果你的脑袋没有它的意思,它会简单地重置它。

git reset filename.txt  

将从当前索引中删除名为 filename.txt 的文件,即“即将提交”区域,而不更改任何其他内容。

您可以使用 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

打开一个窗口 => 从分阶段更改中取消选中您的文件(将提交) 在此处输入图像描述

在 Sourcetree 中,您可以通过 GUI 轻松完成此操作。 您可以检查 Sourcetree 使用哪个命令来取消暂存文件。

我创建了一个新文件并将其添加到 Git。 然后我使用 Sourcetree GUI 取消了它。 这是结果:

取消暂存文件 [08/12/15 10:43] git -c diff.mnemonicprefix=false -c core.quotepath=false -c credential.helper=sourcetree reset -q -- path/to/file/filename.java

Sourcetree 使用reset来取消暂存新文件。

最直观的解决方案之一是使用Sourcetree

您可以从暂存和未暂存中拖放文件

在此处输入图像描述

如果您想恢复最后一次提交,但仍想在本地保留在提交中所做的更改,请使用以下命令:

git reset HEAD~1 --mixed

git reset命令可帮助您修改暂存区或暂存区和工作树。 Git 能够完全按照您的意愿制作提交,这意味着您有时需要撤消对您使用git add暂存的更改所做的更改。

你可以通过调用git reset HEAD <file to change>来做到这一点。 您有两种选择可以完全摆脱更改。 git checkout HEAD <file(s) or path(s)>是一种快速撤消对暂存区和工作树所做更改的方法。

但是,请小心使用此命令,因为它会删除对工作树的所有更改。 Git 不知道这些更改,因为它们从未被提交。 运行此命令后,无法恢复这些更改。

您可以使用的另一个命令是git reset --hard 它对您的工作树同样具有破坏性 - 任何未提交的更改或分阶段的更改在运行后都会丢失。 运行git reset -hard HEADgit checkout HEAD做同样的事情。 它只是不需要文件或路径即可工作。

您可以将--softgit reset一起使用。 它将存储库重置为您指定的提交并暂存所有这些更改。 您已经暂存的任何更改都不会受到影响,工作树中的更改也不会受到影响。

最后,您可以使用--mixed重置工作树,而无需暂存任何更改。 这也会取消暂存的任何更改。

您可以在 git 版本 2.23 之后使用此命令:

git restore --staged <filename>

或者,您可以使用以下命令:

git reset HEAD <filename>

我会使用git restore --staged . git restore --staged <filename>

您也可以使用git rm --cached ,但是git rm命令应该理想地用于已跟踪的文件。

我第一次遇到这个问题时,我在这里找到了这篇文章,从第一个答案中我了解到我应该只做git reset <filename> 它工作得很好。

最后,我碰巧在我的主 git 文件夹中有几个子文件夹。 我发现只做git add . 添加子文件夹中的所有文件,然后git reset我不想添加的几个文件。

现在我有很多文件和子文件夹。 一个接一个地git reset很乏味,但git add . 首先,然后重置几个重/不需要但有用的文件和文件夹。

我发现下面的方法( 这里这里没有记录)相对容易。 我希望它会有所帮助:

假设您有以下情况:

Folder/SubFolder1/file1.txt
Folder/SubFolder2/fig1.png
Folder/SubFolderX/fig.svg
Folder/SubFolder3/<manyfiles>
Folder/SubFolder4/<file1.py, file2.py, ..., file60.py, ...>

您想添加所有文件夹和文件,但不是fig1.png ,而不是SubFolderX ,而不是file60.py并且列表不断增长......

首先,制作/创建一个bash shell script并为其命名。 说, git_add.sh

然后将所有路径添加到您想要git reset前面的所有文件夹和文件git reset -- 随着文件列表的增加,您可以轻松地将路径复制粘贴到脚本git_add.sh中。 git_add.sh脚本应如下所示:

#!/bin/bash

git add .
git reset -- Folder/SubFolder2/fig1.png
git reset -- Folder/SubFolderX
git reset -- Folder/SubFolder4/file60.py

#!/bin/bash很重要。 然后执行source git_add.sh来运行它。 之后,您可以执行git commit -m "some comment" ,如果您已经设置了 Bitbucket/Github,则可以执行git push -u origin master

免责声明:我只在 Linux 中测试过这个。


如果您有很多文件和文件夹始终保留在本地 git 存储库中,但您不希望 git 在执行git add . ,比如说视频和数据文件,你必须学习如何使用.gitignore 也许从这里

git add -A

用于将所有文件添加到您的提交(阶段)。

git reset

与“git add -A”命令相反。 它删除所有暂存(意味着准备好)提交的文件。

同样,要添加要提交的特定文件,我们使用git add <filename>同样,取消暂存(或重置)我们使用 git 添加的特定文件git add我们使用git reset <filename>

git 复位与 git 完全相反。

1 没有调用主干on('add')

我在集合上定义了添加处理程序: 从我的一种观点来看,它正在被调用: 但是,我的收藏夹上的添加处理程序永远不会触发。 实际上,似乎甚至没有调用视图中的成功函数。 但是无论如何都会保存newBookmark,因此不会发生任何错误。 我想念什么? 发布新书签时,No ...

4 'ADD'和'DADD'之间的区别

“ ADD ”和“ DADD ” MIPS指令有什么区别? 我知道' DADD '代表Double Word Add,但我不知道' ADD '和' DADD '之间的区别。 而且,似乎两个指令都具有相同的语法, 例如, ...

5 'object'不包含'Add'的定义

在这一行: 它一直在说 'object'不包含'Add'的定义,也没有扩展方法'Add'可以找到接受'object'类型的第一个参数。 有人可以帮忙吗? ...

7 蓝鹈鹕Add'Em Up项目

我已经在一个名为Add'Em Up的Blue Pelican Java项目上工作了几个小时,但我不知道如何使它工作。 项目描述是这样的: 考虑下面的程序,该程序允许从键盘输入8 + 33 + 1,345 +137之类的字符串。 然后,Scanner对象将加号(和任何相邻的空格)用作定界 ...

2015-04-09 22:34:38 1 2297   java
9 与(“选择器”).rules('add',{…})一起使用

在我的表单中,邮政编码输入位于State输入之前。 因此,我只想在填写我的州输入后才验证邮政编码。 我已经开始工作了。 我还无法弄清楚如何使用jQuery Validation插件的“ depends”。 由于要使用CRM,因此我需要使用.rules('add',{...})来设置验证。 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM