我错误地用命令将文件添加到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 status
... 很多废话滚动的...
=> 妈的,我不想把这些都加进去。
=>。 找到Stack Overflow - 耶
git reset .
。=> fatal: Fatal: Failed to resolve 'HEAD' 作为一个有效的 ref。
进一步发现,在邮件列表中,有'的[bug记录][1]针对这个无益的问题。
而正确的解决方案就在Git状态输出中(是的,我把它当作'废话)。
... .gt;
有待承诺的改变。
(使用"git rm --cached
..." 来取消阶段) ...
解决办法确实是使用git rm --cached FILE
。
请注意其他地方的警告 - git rm
会删除文件的本地工作副本,但如果你使用--缓存则不会。
这里是git help rm
的结果。
--cached >.使用这个选项可以取消阶段,只从索引中删除路径。 使用该选项可以取消阶段,只从索引中删除路径。 使用此选项取消阶段,只从索引中删除路径。 工作树文件,无论是否修改,都会被留下。
我继续使用
git rm --cached .
来删除所有的东西并重新开始。
不过没能成功,因为虽然add .
是递归的,但原来rm
需要-r
才能递归。
叹了口气。
git rm -r --cached .
好了,现在我'又回到了开始的地方。
下次我'要用-n
来做一次干货,看看会增加什么。
git add -n .
在相信 "git help rm "关于"--缓存 "不会破坏任何东西之前,我把所有东西都压缩到了一个安全的地方(如果我拼错了怎么办)。
[1]: http://kerneltrap.org/mailarchive/git/2008/2/13/846664/thread
澄清一下。
git add
将当前工作目录中的更改移到staging区域(索引)。
这个过程叫做staging。 所以最自然的命令就是stage变化(修改的文件)。
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 "的真正*undo是什么?
git reset HEAD <file>
?
还是
git rm --cached <file>
?
严格来说,如果我没有弄错的话。 严格来说,如果我没记错的话,没有.
git add
不能撤销 - 安全地,一般来说。
让我们先回顾一下git add <file>
的实际作用。
如果<file>
之前没有被跟踪,git add
就会将其与当前内容一起添加到缓存中**。
如果<file>
已经被跟踪,git add
将当前内容(快照、版本)保存到缓存中。
在Git中,这个操作仍然叫做添加,(而不是单纯的更新),因为一个文件的两个不同版本(快照)被视为两个不同的项目。
因此,我们确实是在缓存中添加了一个新的项目,并将在以后提交。
有鉴于此,这个问题略显含糊。
我错误地使用命令添加文件... ...
OP'的情况似乎是第一种(未追踪的文件),我们希望用"undo"
从跟踪的项目中删除文件(不只是当前内容)。
如果是这种情况,那么运行git rm --cached <file>
就可以了。
而且我们还可以运行git reset HEAD <file>
。
一般来说,这是比较好的,因为它在两种情况下都能用。
当我们错误地添加了一个已经被跟踪的项目的版本时,它也会进行撤销。
但是有两个注意事项。
首先。 只有一种情况下(正如答案中所指出的),"git reset HEAD "不起作用,但 "git rm --cached "起作用。 一个新的版本库(没有提交)。 但实际上,这只是一个无关紧要的情况。
第二种情况。
要知道,git reset HEAD
并不能神奇地恢复之前缓存的文件内容,它只是从HEAD重新同步。
如果我们误入歧途的git add
覆盖了之前暂存的未提交的版本,我们就无法恢复。
这就是为什么严格来说,我们不能撤销[*]。
例如:{{{5439876}}。
$ 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
命令更新新内容。
使用Git可以很容易地撤销一个已经添加的文件。
要重置已经添加的myfile.txt
,请使用。
git reset HEAD myfile.txt
解释:
当你暂存了不需要的文件后,要撤销,你可以执行git reset
。
Head
是你在本地的文件头,最后一个参数是你的文件名。
我在下图中为你创建了更详细的步骤,包括在这些情况下可能发生的所有步骤。
[![git reset HEAD file][1]][1]
Git的命令涵盖了所有可以想象到的操作,但它需要大量的知识才能正确地进行操作,正因为如此,它最多也是反直觉的......
**你之前做了什么:***
git add .
,或git add <file>
。你想要什么:
git reset head
<!-- language: lang-bash -->
svn revert <file>
IIRC。git reset HEAD
<branch>
的名字,比如<file>
,就用。git checkout -- <file>。
这是很有必要的,因为git reset --hard HEAD
对单个文件不起作用。
<file>
,保留未版本的文件和工作副本中的变化。git rm --cached
<file>
。git rm
这个问题没有明确提出来。
原因是git add
有两层意思。
git rm -缓存文件
撤销。添加一个修改过的文件到暂存区,然后用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 reset
。
但是:
我发现了这个很棒的小贴子,它实际上为 "git unadd "添加了Git命令(嗯,一个别名)。 详情请看[git unadd][2]。
简单地说。
git config --global alias.unadd "reset HEAD"
现在你可以
git unadd foo.txt bar.txt
[1]: https://www.kernel.org/pub/software/scm/git/docs/git-reset.html [2]: https://blog.pivotal.io/labs/labs/git-unadd
使用 "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"。 (revert),"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)
$
当你开始一个新的项目时,这里有一个方法可以避免这个令人烦恼的问题。
git init
。如果你没有任何提交,Git 会让你很难做git reset
。
如果你只是为了有一个小的初始提交,那么之后你就可以随意地进行 "git add -A "和 "git reset",以使一切都正确。
这种方法的另一个好处是,如果你以后遇到行末问题,需要刷新所有文件,那很容易。
请注意,如果你没有指定修订版,那么你必须包含一个分隔符。 我的控制台中的例子。
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 HEAD *.prj
git reset HEAD *.bmp
git reset HEAD *gdb*
等等。