为什么有两种方法可以在Git中取消暂存文件?

有时git建议git rm --cached卸载文件,有时git reset HEAD file。我应该什么时候使用哪个?

D:\code\gt2>git initInitialized 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)##       anothing 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] a0 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)##       bnothing 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#
1303098 次浏览

git rm --cached <filePath>不会取消一个文件,它实际上来自repo(假设它之前已经提交),但将文件留在工作树中(留下一个未跟踪的文件)。

git reset -- <filePath>取消舞台给定文件的任何分阶段更改。

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

更新git 2.24
在这个较新版本的git中,您可以使用git restore --staged而不是git resetgit文档.

git rm --cached用于从索引中删除文件。如果文件已经在存储库中,git rm --cached将从索引中删除文件,将其留在工作目录中,现在提交也将从存储库中删除它。基本上,提交后,您将取消文件的版本并保留本地副本。

git reset HEAD file(默认情况下使用--mixed标志)是不同的,在文件已经在repo中的情况下,它将文件的索引版本替换为repo(HEAD)中的索引版本,有效地将修改卸载到它。

在未版本化文件的情况下,它将取消整个文件,因为文件不在HEAD中。在这方面,git reset HEAD filegit rm --cached是相同的,但它们不相同(如在存储库中已有文件的情况下所解释的)

对于Why are there 2 ways to unstage a file in 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-addedno changes added to commit (use "git add" and/or "git commit -a")

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

编辑:git checkout HEAD to-be-modified to-be-removed也适用于取消暂存,但从工作区中完全删除更改

更新git 2.23.0:命令会不时发生变化。现在,git status表示:

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

…适用于所有三种变化

在我看来,git rm --cached <file>从索引中删除文件而不从普通git rm <file>将其从目录中删除,就像OSrm <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 added的文件),那么这两个命令具有相同的效果,因此看起来这是“两种做事方式”。

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

**由于git重置命令的名字,我在很长一段时间内都很害怕使用它,直到今天我仍然经常查找语法以确保我不会搞砸。(date:我终于花时间在tldr页面中总结了git reset的用法,所以现在我有了一个更好的关于它是如何工作的心理模型,以及当我忘记一些细节时的快速参考。)

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

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

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

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

对不起-没有真正回答你的问题,但只是指出另一种方法来取消我经常使用的文件(我喜欢Ryan Stewart和waldyrious的答案);)我希望它有帮助。

如果您不小心暂存了不想提交的文件,并且希望确保保留更改,您还可以使用:

git stashgit stash pop

这将执行重置到HEAD并重新应用您的更改,允许您重新执行单个文件以进行提交。如果您忘记为拉取请求创建功能分支(git stash ; git checkout -b <feature> ; git stash pop),这也很有帮助。

假设您通过git add <folder>stage了整个目录,但您想从分阶段列表(即运行git status时生成的列表)中排除一个文件,并保持排除文件中的修改(您正在处理某些事情并且还没有准备好提交,但您不想丢失您的工作…)。

git reset <file>

当您运行git status时,您将看到您resetunstaged的任何文件,而您added的其余文件仍在staged列表中。

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--cache…”取消执行)

  • git是一个指针系统

  • 您还没有提交将指针更改为

  • 从指向的存储桶中取出文件的唯一方法是删除您告诉git监视更改的文件

2.

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

git提交

  • 你承诺,“保存

3.

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

(使用“git重置HEAD…”取消执行)

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

只需使用:

git reset HEAD <filename>

这会取消文件的阶段并保留您对其所做的更改,因此您可以根据需要更改分支并将这些文件git add改为另一个分支。所有更改都保留。

仅适用于2.23及以上版本,

除了这些建议,您还可以使用git restore --staged <file>为了unstage文件。

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

git restore --staged abc.html

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

git restore --staged .

请注意空格和点(.),这意味着考虑暂存所有文件。

取消暂存文件(取消git add)

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

丢弃局部更改

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

git恢复file1.jsfile2.js#恢复工作目录中的多个文件

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

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