简体   繁体   English

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

[英]Why are there two ways to unstage a file in Git?

Sometimes git suggests git rm --cached to unstage a file, sometimes git reset HEAD file .有时 git 建议git rm --cached取消暂存文件,有时git reset HEAD file When should I use which?我什么时候应该使用哪个?

EDIT:编辑:

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
#

git rm --cached <filePath> does not unstage a file, it actually stages the removal of the file(s) from the repo (assuming it was already committed before) but leaves the file in your working tree (leaving you with an untracked file). git rm --cached <filePath>不会取消git rm --cached <filePath>文件,它实际上会git rm --cached <filePath>从存储库中删除文件(假设它之前已经提交)但将文件留在您的工作树中(让您留下未跟踪的文件)文件)。

git reset -- <filePath> will unstage any staged changes for the given file(s). git reset -- <filePath>取消暂存给定文件的任何暂存更改。

That said, if you used git rm --cached on a new file that is staged, it would basically look like you had just unstaged it since it had never been committed before.也就是说,如果您在git rm --cached的新文件上使用git rm --cached ,它基本上看起来就像您刚刚取消暂存,因为它以前从未被提交过。

Update git 2.24更新 git 2.24
In this newer version of git you can use git restore --staged instead of git reset .在这个较新版本的 git 中,您可以使用git restore --staged而不是git reset See git docs .请参阅git 文档

git rm --cached is used to remove a file from the index. git rm --cached用于从索引中删除文件。 In the case where the file is already in the repo, git rm --cached will remove the file from the index, leaving it in the working directory and a commit will now remove it from the repo as well.如果文件已经在 repo 中, git rm --cached将从索引中删除该文件,将其保留在工作目录中,现在提交也会将其从 repo 中删除。 Basically, after the commit, you would have unversioned the file and kept a local copy.基本上,在提交之后,您将取消版本化文件并保留本地副本。

git reset HEAD file ( which by default is using the --mixed flag) is different in that in the case where the file is already in the repo, it replaces the index version of the file with the one from repo (HEAD), effectively unstaging the modifications to it. git reset HEAD file (默认情况下使用--mixed标志)的不同之处在于,在文件已经在 repo 中的情况下,它将文件的索引版本替换为来自 repo (HEAD) 的索引版本,有效地取消对它的修改

In the case of unversioned file, it is going to unstage the entire file as the file was not there in the HEAD.在未版本化文件的情况下,它将取消整个文件的暂存,因为该文件不在 HEAD 中。 In this aspect git reset HEAD file and git rm --cached are same, but they are not same ( as explained in the case of files already in the repo)在这方面git reset HEAD filegit rm --cached是相同的,但它们不一样(如已在 repo 中的文件的解释)

To the question of Why are there 2 ways to unstage a file in git?关于Why are there 2 ways to unstage a file in git?取消Why are there 2 ways to unstage a file in git? - there is never really only one way to do anything in git. - 在 git 中做任何事情的方法从来都不是只有一种。 that is the beauty of it :)这就是它的美妙之处:)

Quite simply:很简单:

  • git rm --cached <file> makes git stop tracking the file completely (leaving it in the filesystem, unlike plain git rm *) git rm --cached <file>使 git 完全停止跟踪文件(将其留在文件系统中,与普通的git rm * 不同)
  • git reset HEAD <file> unstages any modifications made to the file since the last commit (but doesn't revert them in the filesystem, contrary to what the command name might suggest**). git reset HEAD <file>取消自上次提交以来对git reset HEAD <file>所做的任何修改(但不会在文件系统中恢复它们,这与命令名称可能暗示的相反**)。 The file remains under revision control.该文件仍处于修订控制之下。

If the file wasn't in revision control before (ie you're unstaging a file that you had just git add ed for the first time), then the two commands have the same effect, hence the appearance of these being "two ways of doing something".如果该文件之前不在修订控制中(即您正在取消git add您刚刚git add ed 的第一次文件),那么这两个命令具有相同的效果,因此它们的外观是“两种方式做某事”。

* Keep in mind the caveat @DrewT mentions in his answer, regarding git rm --cached of a file that was previously committed to the repository. * 请记住@DrewT 在他的回答中提到的警告,关于之前提交到存储库的文件的git rm --cached In the context of this question, of a file just added and not committed yet, there's nothing to worry about.在这个问题的上下文中,对于刚刚添加但尚未提交的文件,没有什么可担心的。

** I was scared for an embarrassingly long time to use the git reset command because of its name -- and still today I often look up the syntax to make sure I don't screw up. ** 由于它的名字,我很长时间都害怕使用 git reset 命令——直到今天我仍然经常查看语法以确保我没有搞砸。 ( update : I finally took the time to summarize the usage of git reset in a tldr page , so now I have a better mental model of how it works, and a quick reference for when I forget some detail.) 更新:我终于花时间在 tldr 页面中总结了git reset的用法,所以现在我对它的工作方式有了一个更好的心理模型,以及当我忘记一些细节时的快速参考。)

This thread is a bit old, but I still want to add a little demonstration since it is still not an intuitive problem:这个线程有点老了,但我还是想补充一点演示,因为它仍然不是一个直观的问题:

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 (without -q ) gives a warning about the modified file and its exit code is 1 which will be considered as an error in a script. git reset HEAD (不带-q )给出关于修改文件的警告,其退出代码为 1,这将被视为脚本中的错误。

Edit: git checkout HEAD to-be-modified to-be-removed also works for unstaging, but removes the change completely from the workspace编辑: git checkout HEAD to-be-modified to-be-removed也适用于取消暂存,但从工作区中完全删除更改

Update git 2.23.0: From time to time, the commands change.更新 git 2.23.0:命令会不时更改。 Now, git status says:现在, git status说:

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

... which works for all three types of change ... 适用于所有三种类型的变化

if you've accidentally staged files that you would not like to commit, and want to be certain you keep the changes, you can also use:如果您不小心暂存了您不想提交的文件,并希望确保保留更改,您还可以使用:

git stash
git stash pop

this performs a reset to HEAD and re-applies your changes, allowing you to re-stage individual files for commit.这会重置 HEAD 并重新应用您的更改,从而允许您重新暂存单个文件以进行提交。 this is also helpful if you've forgotten to create a feature branch for pull requests ( git stash ; git checkout -b <feature> ; git stash pop ).如果您忘记为拉取请求创建功能分支( git stash ; git checkout -b <feature> ; git stash pop ),这也很有帮助。

These 2 commands have several subtle differences if the file in question is already in the repo and under version control (previously committed etc.):如果有问题的文件已经在 repo 中并且在版本控制之下(以前提交等),这 2 个命令有几个细微的区别:

  • git reset HEAD <file> unstages the file in the current commit. git reset HEAD <file>在当前提交中取消暂存文件。
  • git rm --cached <file> will unstage the file for future commits also. git rm --cached <file>也将取消git rm --cached <file>文件以备将来提交。 It's unstaged untill it gets added again with git add <file> .在使用git add <file>再次git add <file>它是未git add <file>

And there's one more important difference:还有一个更重要的区别:

  • After running git rm --cached <file> and push your branch to the remote, anyone pulling your branch from the remote will get the file ACTUALLY deleted from their folder, even though in your local working set the file just becomes untracked (ie not physically deleted from the folder).运行后git rm --cached <file> ,并把你的分支到远程,任何人从远程拉你的分公司将充分利用自己的文件夹中实际删除文件,即使在您的本地工作仅有变成未被跟踪的文件(即不从文件夹中物理删除)。

This last difference is important for projects which include a config file where each developer on the team has a different config (ie different base url, ip or port setting) so if you're using git rm --cached <file> anyone who pulls your branch will have to manually re-create the config, or you can send them yours and they can re-edit it back to their ip settings (etc.), because the delete only effects people pulling your branch from the remote.最后一个区别对于包含配置文件的项目很重要,其中团队中的每个开发人员都有不同的配置(即不同的基本 url、ip 或端口设置),因此如果您使用git rm --cached <file>任何人您的分支必须手动重新创建配置,或者您可以将您的配置发送给他们,他们可以将其重新编辑回他们的 ip 设置(等),因为删除只会影响人们从远程拉出您的分支。

Let's say you stage a whole directory via git add <folder> , but you want to exclude a file from the staged list (ie the list that generates when running git status ) and keep the modifications within the excluded file (you were working on something and it's not ready for commit, but you don't want to lose your work...).比方说,你stage通过整个目录git add <folder> ,但要排除一个文件从分级列表(即运行时产生的列表git status ),并保持已排除的文件中修改(您正在使用的东西它尚未准备好提交,但您不想丢失您的工作......)。 You could simply use:你可以简单地使用:

git reset <file>

When you run git status , you will see that whatever file(s) you reset are unstaged and the rest of the files you added are still in the staged list.当您运行git status ,您将看到您reset任何文件unstaged ,而您added的其余文件仍在staged列表中。

1. 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

(use "git rm --cached ..." to unstage) (使用“git rm --cached ...”取消暂存)

  • git is a system of pointers git 是一个指针系统

  • you do not have a commit yet to change your pointer to您还没有提交将指针更改为

  • the only way to 'take files out of the bucket being pointed to' is to remove files you told git to watch for changes “从指向的存储桶中取出文件”的唯一方法是删除您告诉 git 监视更改的文件

2. 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 commit -ma git commit -ma

  • you commited, ' saved '你承诺,“保存

3. 3.

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

(use "git reset HEAD ..." to unstage) (使用“git reset HEAD ...”取消暂存)

  • you made a commit in your code at this time您此时在代码中进行了提交
  • now you can reset your pointer to your commit ' revert back to last save '现在您可以将指针重置为您的提交“恢复到上次保存

Just use:只需使用:

git reset HEAD <filename>

This unstages the file and keeps the changes you did to it, so you can, in turn, change branches if you wanted and git add those files to another branch instead.这会取消暂存文件并保留您对它所做的更改,因此您可以反过来,如果需要,更改分支,然后git add这些文件git add到另一个分支。 All changes are kept.保留所有更改。

I'm surprised noone mentioned the git reflog ( http://git-scm.com/docs/git-reflog ):我很惊讶没有人提到 git reflog ( http://git-scm.com/docs/git-reflog ):

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

The reflog is a git history that not only tracks the changes to the repo, but also tracks the user actions (Eg. pull, checkout to different branch, etc) and allows to undo those actions. reflog 是一个 git 历史记录,它不仅可以跟踪对 repo 的更改,还可以跟踪用户操作(例如拉取、结帐到不同分支等)并允许撤消这些操作。 So instead of unstaging the file that was mistakingly staged, where you can revert to the point where you didn't stage the files.因此,您无需取消暂存错误暂存的文件,而是可以恢复到未暂存文件的位置。

This is similar to git reset HEAD <file> but in certain cases may be more granular.这类似于git reset HEAD <file>但在某些情况下可能更精细。

Sorry - not really answering your question, but just pointing yet another way to unstage files that I use quite often (I for one like answers by Ryan Stewart and waldyrious very much.) ;) I hope it helps.抱歉 - 没有真正回答你的问题,只是指出了另一种我经常使用的取消暂存文件的方法(我非常喜欢 Ryan Stewart 和 waldyrious 的答案。);)我希望它有所帮助。

For versions 2.23 and above only,仅适用于 2.23 及以上版本,

Instead of these suggestions, you could use git restore --staged <file> in order to unstage the file(s).代替这些建议,您可以使用git restore --staged <file> ,以unstage文件(县)。

在我看来, git rm --cached <file>会从索引中删除文件,而不会将其从普通git rm <file>将同时执行这两项操作的目录中删除,就像操作系统rm <file>会删除文件一样从目录中删除其版本控制。

In the newer version that is > 2.2 you can use git restore --staged <file_name> .在 > 2.2 的较新版本中,您可以使用git restore --staged <file_name> Note here If you want to unstage (move to changes) your files one at a time you use above command with your file name.请注意这里如果您想一次取消暂存(移动到更改)您的文件,请使用上述命令和您的文件名。 eg例如

git restore --staged abc.html

Now if you want unstage all your file at once, you can do something like this现在,如果您想一次取消所有文件的暂存,您可以执行以下操作

git restore --staged .

Please note space and dot (.) which means consider staged all files.请注意空格和点(.),这意味着考虑暂存所有文件。

Unstaging files (undoing git add)取消暂存文件(撤消 git add)

git restore --staged file.js # Copies the last version of file.js from repo to index git restore --staged file.js # 将最新版本的 file.js 从 repo 复制到 index

discarding local changes丢弃本地更改

git restore file.js # Copies file.js from index to working directory git restore file.js # 将 file.js 从索引复制到工作目录

git restore file1.js file2.js # Restores multiple files in working directory git restore file1.js file2.js # 恢复工作目录下的多个文件

git restore .混帐恢复。 # Discards all local changes (except untracked files) # 丢弃所有本地更改(未跟踪的文件除外)

git clean -fd # Removes all untracked files git clean -fd # 删除所有未跟踪的文件

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

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