git rm will remove entries from the staging area. This is a bit different from git reset HEAD which "unstages" files. By "unstage" I mean it reverts the staging area to what was there before we started modifying things. git rm on the other hand just kicks the file off the stage entirely, so that it's not included in the next commit snapshot, thereby effectively deleting it. By default, a git rm file will remove the file from the staging area entirely and also off your disk > (the working directory). To leave the file in the working directory, you can use git rm --cached.
But what exactly is the difference between git rm --cached asd
and git reset head -- asd
?
There are three places where a file, say, can be - the (committed) tree, the index and the working copy. When you just add a file to a folder, you are adding it to the working copy.
When you do something like git add file
you add it to the index. And when you commit it, you add it to the tree as well.
It will probably help you to know the three more common flags in git reset
:
git reset [--
Now, when you do something like git reset HEAD
, what you are actually doing is git reset HEAD --mixed
and it will "reset" the index to the state it was before you started adding files / adding modifications to the index (via git add
). In this case, no matter what the state of the working copy was, you didn't change it a single bit, but you changed the index in such a way that is now in sync with the HEAD of the tree. Whether git add
was used to stage a previously committed but changed file, or to add a new (previously untracked) file, git reset HEAD
is the exact opposite of git add
.
git rm
, on the other hand, removes a file from the working directory and the index, and when you commit, the file is removed from the tree as well. git rm --cached
, however, removes the file from the index alone and keeps it in your working copy. In this case, if the file was previously committed, then you made the index to be different from the HEAD of the tree and the working copy, so that the HEAD now has the previously committed version of the file, the index has no file at all, and the working copy has the last modification of it. A commit now will sync the index and the tree, and the file will be removed from the tree (leaving it untracked in the working copy). When git add
was used to add a new (previously untracked) file, then git rm --cached
is the exact opposite of git add
(and is pretty much identical to git reset HEAD
).
Git 2.25 introduced a new command for these cases, git restore
, but as of Git 2.28 it is described as “experimental” in the man page, in the sense that the behavior may change.
Perhaps an example will help:
git rm --cached asd
git commit -m "the file asd is gone from the repository"
versus
git reset HEAD -- asd
git commit -m "the file asd remains in the repository"
Note that if you haven't changed anything else, the second commit won't actually do anything.
--
is used to separate command options from file names. If there were both a branch and a file named asd
, then git reset HEAD asd
would be ambiguous. The --
says "everything following this is a file name".
git reset HEAD <file>
exactly the same as git rm --cached <file>
and then git add --intent-to-add <file>
?
git rm --cached file
will remove the file from the stage. That is, when you commit the file will be removed. git reset HEAD -- file
will simply reset file in the staging area to the state where it was on the HEAD commit, i.e. will undo any changes you did to it since last commiting. If that change happens to be newly adding the file, then they will be equivalent.
git rm --cached file
is kinda the opposite of git add
, this answer made a lot of sense to me, and was pretty succinct. Almost as short as this comment ;)
git rm --cached file
is not the opposite of git add file
. The behavior happens to be the opposite of git add file
in the specific case where you have added a new, previously untracked file. In every other case the opposite of git add file
is git reset HEAD file
. git reset HEAD file
also reverses git add file
in the first case (adding an untracked file), and in every case, which is why it's what git suggests to do if you want to reverse a git add.
git reset HEAD file
will not have any effect, you will only get fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree.
Success story sharing
git rm --cached
thegit diff
command doesn't show any diff, butgit diff --cached
shows the diff, as if it is still cached. Thegit status
however shows the file as beingUntracked
. Seems kind of inconsistent.git reset --mixed
. I was a little confused by the statement thatgit rm --cached
is the opposite ofgit add
. Taken literally, it is incorrect and could cause damage. In my case, I usedgit add
to add a modified file to the staging area and wanted the opposite of "that add" not the initial add of the file. +Greg Hewgill's answer helped me get a clearer picture.git rm --cached
'is the exact opposite ofgit add file
' is misleading.git reset file
is closer to being the opposite ofgit add file
.