Why are there 2 ways to unstage a file in git?

Sometimes git suggests git rm --cached to unstage a file, sometimes git reset HEAD file . When should I use which?

EDIT:

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

D:codegt2>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:codegt2>git add a

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

D:codegt2>touch b

D:codegt2>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:codegt2>git add b

D:codegt2>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 reset <filePath> will unstage any staged changes for the given file(s).

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 is used to remove a file from the index. 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. 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.

In the case of unversioned file, it is going to unstage the entire file as the file was not there in the 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)

To the question of Why are there 2 ways to unstage a file in git? - there is never really only one way to do anything in 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 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**). 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".

    * Keep in mind the caveat @DrewT mentions in his answer, regarding git rm --cached of a file that was previously committed to the repository. 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. ( 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.)

    链接地址: http://www.djcxy.com/p/928.html

    上一篇: 我如何使用jQuery按名称选择元素?

    下一篇: 为什么有两种方法来卸载git中的文件?