我错误地使用以下命令将文件添加到了 Git:
git add myfile.txt
我还没有运行git commit
。有一种方法可以撤消此操作,以便这些文件不会包含在提交中?
您可以在提交之前撤消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 rm --cached <added_file_to_undo>
推理:
当我是新手时,我首先尝试
git reset .
(撤消我的整个初始添加),只是得到了此信息(不是这样),有帮助:
fatal: Failed to resolve 'HEAD' as a valid ref.
事实证明,这是因为 HEAD ref(分支?)在第一次提交之后才存在。也就是说,如果您的工作流程(例如我的)类似于以下内容,您将遇到与我相同的初学者问题:
git init
git add .
git status
... 很多废话
=> 该死,我不想添加所有这些内容。
谷歌 “撤消 git 添加”
=> 查找堆栈溢出 - 是
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
将更改从当前工作目录移动到暂存区 (索引)。
此过程称为暂存 。所以最自然的命令阶段的变化(变更的文件)是明显的:
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 reset
' 将其从索引中删除后,它似乎仍会占据.git
目录中的空间。
这没什么好担心的。该文件确实仍在存储库中,但仅作为 “松散对象”。不会将其复制到其他存储库(通过克隆,推送),最终将回收该空间 - 尽管可能不会很快。如果您着急,可以运行:
git gc --prune=now
更新 (以下是我的尝试,以消除因最不满意的答案而引起的一些混乱):
那么,哪个是git add
的真正撤消 ?
git reset HEAD <file>
要么
git rm --cached <file>
严格来说,如果我没记错的话: 没有 。
git add
无法撤消 - 通常来说是安全的。
让我们首先回顾一下git add <file>
实际作用:
如果<file>
先前未被跟踪 ,则git add
会将其及其当前内容添加到缓存中 。
如果<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),然后通过 commit git commit -a
命令更新新内容,这并不是很关键。
*(编辑:以上内容实际上是正确的,但是仍然可能有一些稍作修改 / 令人费解的方法来恢复已上演但未提交但随后被覆盖的更改 - 请参阅 Johannes Matokic 和 iolsmit 的评论)
git rm --cached . -r
将递归 “取消添加” 从当前目录添加的所有内容
跑
git gui
并手动删除所有文件,或者选择所有文件并单击从提交中取消登台按钮。
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
具有两个含义:
git rm --cached file
撤消。 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