1

If I have a file in the staging area (showing in git diff --cached) and I want to remove it completely how do I do that?
Doing

git reset HEAD -- file  
git checkout -- file  

does it but is there 1 command for these 2 actions?

Jim
  • 3,845
  • 3
  • 22
  • 47

3 Answers3

7

Yes:

git checkout HEAD -- file

does the trick.

Longer version with a lot of background

There are many (too many, sometimes) things to know about this. First, the index (also known as the staging area or the cache) holds all files-to-be-committed at all times. In fact, each file's presence in the index is what means the file will be committed, in the form it has in the index. This is why you have to keep doing git add file all the time: Git won't copy it from the work-tree into the index, overwriting the old index version, until you tell Git to do so.

When you initially check out some commit, the index normally holds a copy of every file that's in that commit as well. There are some exceptions (see Checkout another branch when there are uncommitted changes on the current branch for details), but usually, the initial setup is:

  HEAD      index     work-tree
-------------------------------
README.md  README.md  README.md
file1.txt  file1.txt  file1.txt

and so on, with all three versions of each file matching.

There are some slight but important differences between each copy, though:

  • The copy in the commit, in HEAD, is read-only. Nothing can change this copy. (Of course, HEAD itself can change to be another, different, commit; the different commit can have a different copy of the file, or maybe not have the file at all.) The committed copy of the file is in a special Git-only format.

  • The copy in the index / staging-area is read/write. This copy is also in the special Git-only format, though. You can at any time copy a different version of that file into the index, or even remove the index entry.

  • The copy in the work-tree is in your computer's normal format. You can do anything you like with it, subject to whatever limits your computer imposes.

What git status does—well, one of the many things it does—is to run two comparisons:

  • What's in HEAD vs what's in the index. Whatever is different, Git lists as staged for commit.

  • What's in the index vs what's in the work-tree. Whatever is different, Git lists as not staged for commit.

This means you don't have to wade through huge lists of everything that's the same; you only see what's different.

git add = copy from work-tree to index

Using git add path copies the work-tree version into the index. That's pretty simple! Of course, Git being Git, there are more varieties of git add, but we will just ignore them for now. :-)

git reset = ... well, it's complicated

The git reset command does too many different things. However, if you stick with git reset -- path, it simplifies a lot: it means copy from the HEAD commit to the index. The work-tree copy remains untouched.

git checkout = copy from ... well, it's complicated too

The git checkout command, like git reset, does too many different things. However, if you stick with these two forms, we get two things that are easy to explain:

  • git checkout -- path copies from the index to the work-tree.

  • git checkout HEAD -- path copies from the HEAD commit to the index, and then from the index to the work-tree.

There's one option missing here: there is no easy way to copy from HEAD commit to the work-tree, bypassing the index. (There are a few ways to do this but they have certain caveats.)

You cannot write on the HEAD version, so there is no way to copy into HEAD. Instead, you will run git commit, which makes a new commit, freezing the index copy (of every file!) forever. The new commit then becomes the HEAD commit. The fact that all the files are already in their final form in the index, when you run git commit, is part of what makes git commit so fast.

torek
  • 448,244
  • 59
  • 642
  • 775
  • I have never seen this command before. I need to study your detailed answer! – Jim Apr 09 '18 at 19:57
  • When doing `git reset` the file is removed from the staging area but the changes are in my working tree. What do you mean by "untouched"? Also is the `--` needed in the `git checkout`? – Jim Apr 10 '18 at 08:31
  • By "untouched", I mean the command itself makes no changes to the work-tree copy of the file. You may or may not have made changes to the work-tree copy, but `git reset -- ` does not make changes to it. As for the `--`, this is required if and only if the Git command might think that the file name means something else. For instance, what if you have a file named `master`, or a file named `-f`? These look like branch names and command options. The `--` makes sure Git knows which arguments are which. It's a good habit to get into using `--` always. – torek Apr 10 '18 at 14:30
0

You can use git reset filename.txt

This will remove a file named filename.txt from the the staging area.

You can also use git reset to unstage all files.

Good luck!

Fabián Montero
  • 1,613
  • 1
  • 16
  • 34
0

To remove a single file from the staging area, you can just use:

git reset HEAD -- <file>

To remove a whole directory or folder from the staging area, you can just use:

git reset HEAD -- <directoryName>

For newer versions of Git, You can also use: git restore --staged <file>.

Sometimes you may need to remove cache also: git rm -r --cached .

naib khan
  • 928
  • 9
  • 16