有时git会建议git rm——cached来取消文件,有时git会重置HEAD文件。什么时候用哪个?

D:\code\gt2>git init
Initialized empty Git repository in D:/code/gt2/.git/
D:\code\gt2>touch a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       a
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   a
#
D:\code\gt2>git commit -m a
[master (root-commit) c271e05] a
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a

D:\code\gt2>touch b

D:\code\gt2>git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       b
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add b

D:\code\gt2>git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#

>并不取消文件,它实际上是从repo中删除文件(假设它之前已经提交),但将文件留在你的工作树中(留下一个未跟踪的文件)。

git reset——<filePath>将取消对给定文件的任何阶段性更改。

也就是说,如果您使用缓存在一个新文件上的git rm—,它基本上看起来就像您刚刚取消了它的暂存,因为它之前从未提交过。

更新git 2.24 在这个新版本的git中,你可以使用git restore - staging而不是git reset。 参见git文档。


Git rm——cached用于从索引中删除文件。在文件已经在repo的情况下,git rm——cached将从索引中删除该文件,将其留在工作目录中,现在提交也将从repo中删除该文件。基本上,在提交之后,您将取消该文件的版本控制,并保留一个本地副本。

git重置HEAD文件(默认使用——mixed标志)的不同之处在于,在文件已经在repo的情况下,它会用repo (HEAD)中的索引版本替换文件的索引版本,有效地取消对它的修改。

在未版本化文件的情况下,它将取消整个文件,因为该文件不在HEAD中。在这方面,git reset HEAD file和git rm——cached是一样的,但它们是不一样的(就像已经在repo中的文件一样)

对于为什么在git中有两种方法取消文件的问题?-在git中从来没有真正只有一种方法来做任何事情。这就是它的美妙之处:)


这个线程有点老了,但我仍然想添加一个小演示,因为它仍然不是一个直观的问题:

me$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   to-be-added
#   modified:   to-be-modified
#   deleted:    to-be-removed
#

me$ git reset -q HEAD to-be-added

    # ok

me$ git reset -q HEAD to-be-modified

    # ok

me$ git reset -q HEAD to-be-removed

    # ok

# or alternatively:

me$ git reset -q HEAD to-be-added to-be-removed to-be-modified

    # ok

me$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   to-be-modified
#   deleted:    to-be-removed
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   to-be-added
no changes added to commit (use "git add" and/or "git commit -a")

git reset HEAD(不带-q)给出关于修改文件的警告,其退出码为1,这将被视为脚本中的错误。

Edit: git签出要修改要删除的HEAD也适用于取消暂存,但会将更改完全从工作空间中删除

更新git 2.23.0:命令会不时发生变化。现在,git状态显示:

  (use "git restore --staged <file>..." to unstage)

... 哪种对这三种变化都有效


在我看来,git rm——cached <file>从索引中删除了文件,而没有从目录中删除它,而普通的git rm <file>将两者都做,就像OS rm <file>将从目录中删除文件而没有删除它的版本。


如果有问题的文件已经在repo中并且处于版本控制之下(以前提交过等),这两个命令有几个微妙的区别:

git reset HEAD <file>取消当前提交的文件。 Git rm——cached <file>将取消该文件以供将来提交。直到git add <file>再次添加它之前,它都是不暂存的。

还有一个更重要的区别:

在运行git rm——cached <file>并将你的分支推到远程,任何从远程拉你的分支的人都会从他们的文件夹中实际删除这个文件,即使在你的本地工作集中,这个文件只是变得不被跟踪(即没有从文件夹中物理删除)。

最后一个区别对于包含配置文件的项目很重要,其中团队中的每个开发人员都有不同的配置(即不同的基本url, ip或端口设置),所以如果你使用git rm——cached <file>,任何拉你的分支的人都必须手动重新创建配置,或者你可以将你的配置发送给他们,他们可以重新编辑回他们的ip设置(等),因为删除只会影响从远程拉你的分支的人。


很简单:

Git rm——cached <file>使Git完全停止跟踪文件(将其留在文件系统中,不像普通的Git rm*) git reset HEAD <file>取消自上次提交以来对文件所做的任何修改(但不会在文件系统中恢复它们,这与命令名称可能暗示的**相反)。该文件仍处于修订控制之下。

如果文件之前不在版本控制中(例如,您正在取消git第一次添加的文件),那么这两个命令具有相同的效果,因此看起来这是“做某件事的两种方式”。

*请记住@DrewT在他的回答中提到的警告,关于git rm——缓存之前提交到存储库的文件。在这个问题的上下文中,对于一个刚刚添加但尚未提交的文件,没有什么可担心的。

**因为git的名字,我很长一段时间都不敢使用git reset命令——直到今天我还经常查看它的语法,以确保我不会搞砸。(更新:我终于花时间在tldr页面中总结了git重置的用法,所以现在我对它的工作原理有了更好的心理模型,当我忘记一些细节时,也有了一个快速的参考。)


我很惊讶没有人提到git reflog (http://git-scm.com/docs/git-reflog):

# git reflog
<find the place before your staged anything>
# git reset HEAD@{1}

reflog是一个git历史记录,它不仅跟踪对repo的更改,还跟踪用户的操作(例如。拉,签出到不同的分支等),并允许撤销这些操作。因此,与其取消被错误地暂存的文件,还不如恢复到没有暂存文件的位置。

这类似于git reset HEAD <file>,但在某些情况下可能更细粒度。

抱歉,我并没有真正回答你的问题,只是指出了另一种方法来取消我经常使用的文件(我非常喜欢Ryan Stewart和waldyrious的答案);)我希望这能有所帮助。


如果你无意中暂存了不想提交的文件,并且想要确保保留更改,你也可以使用:

git stash
git stash pop

这将执行HEAD重置并重新应用您的更改,允许您重新提交单个文件。如果你忘记了为pull请求创建一个特性分支(git stash;Git checkout -b <feature>;Git stash pop)。


假设你通过git add <folder>暂存整个目录,但是你想从暂存列表(即运行git状态时生成的列表)中排除一个文件,并将修改保留在排除的文件中(你正在做一些事情,它还没有准备好提交,但你不想失去你的工作…)你可以简单地使用:

Git重置<文件>

当您运行git status时,您将看到您重置的任何文件都是非暂存的,而您添加的其余文件仍然在暂存列表中。


1.

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   a

(使用“git rm—cached…”取消阶段)

Git是一个指针系统 您还没有要更改指针的提交 “从指向的桶中取出文件”的唯一方法是删除你告诉git观察变化的文件

2.

D:\code\gt2>git commit -m a
[master (root-commit) c271e05] a
0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 a

Git提交-m a

你承诺了,“拯救了”

3.

D:\code\gt2>git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#

(使用“git reset HEAD…”取消舞台)

此时,您在代码中进行了一次提交 现在你可以重置指针指向你提交的"恢复到上次保存"


只使用:

git重置HEAD <文件名>

这将取消该文件并保留您对其所做的更改,因此您可以反过来更改分支,git会将这些文件添加到另一个分支。保留所有更改。


仅适用于版本2.23及以上,

除了这些建议,你可以使用 Git恢复—staging <文件>,以便取消文件的阶段。


在> 2.2的新版本中,你可以使用git restore——staging <file_name>。 请注意这里 如果你想一次取消(移动到更改)你的文件,你可以使用上面的命令和你的文件名。如

git restore --staged abc.html

现在,如果您想一次性取消所有文件,您可以这样做

git restore --staged .

请注意空格和点(.)表示考虑将所有文件分段。


取消暂存文件(取消git添加)

将file.js的最后一个版本从repo复制到index

丢弃局部更改

将file.js从索引复制到工作目录

file2.js #恢复工作目录下的多个文件

Git恢复。#丢弃所有本地更改(除了未跟踪的文件)

git clean -fd #删除所有未跟踪的文件