641

I accidentally added a lot of temporary files using git add -A

I managed to unstage the files using the following commands and managed to remove the dirty index.

git ls-files -z | xargs -0 rm -f git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached 

The above commands are listed in the git help rm. But sadly, my files were also deleted on execution, even though I had given cache option. How can I clear the index without losing the content?

Also it would be helpful if someone can explain the way this pipe operation works.

3
  • 9
    rm -f is not a git command and doesn't have a --cached option. Your local files were deleted before you executed git rm so I don't think you can legitimately blame git rm for anything. Commented Aug 18, 2011 at 7:12
  • 10
    @sarat, please consider changing the correct answer to the highly upvoted answer from Ian Maddox, as the git reset --hard is not the correct answer and will in fact delete the content. This will confuse users - as it did me. Commented Mar 24, 2015 at 18:38
  • 2
    @sarat as Marco says, go on. This page gets a lot of traffic. Commented Mar 26, 2015 at 8:26

10 Answers 10

1333

git reset

If all you want is to undo an overzealous "git add" run:

git reset 

Your changes will be unstaged and ready for you to re-add as you please.


DO NOT RUN git reset --hard.

It will not only unstage your added files, but will revert any changes you made in your working directory. If you created any new files in working directory, it will not delete them though.

Sign up to request clarification or add additional context in comments.

2 Comments

I often find I have to perform git checkout -- * as well
Fun (and useful) fact: git stash can save your most recent changes, even when you git reset --hard incorrectly
39

2019 update

As pointed out by others in related questions (see here, here, here, here, here, here, and here), you can now unstage a file with git restore --staged <file>.

To unstage all the files in your project, run the following from the root of the repository (the command is recursive):

git restore --staged . 

If you only want to unstage the files in a directory, navigate to it before running the above or run:

git restore --staged <directory-path> 

Notes

  • git restore was introduced in July 2019 and released in version 2.23.
    With the --staged flag, it restores the content of the working tree from HEAD (so it does the opposite of git add and does not delete any change).

  • This is a new command, but the behaviour of the old commands remains unchanged. So the older answers with git reset or git reset HEAD are still perfectly valid.

  • When running git status with staged uncommitted file(s), this is now what Git suggests to use to unstage file(s) (instead of git reset HEAD <file> as it used to prior to v2.23).

Comments

36

If you have a pristine repo (or HEAD isn't set)[1] you could simply

rm .git/index 

Of course, this will require you to re-add the files that you did want to be added.


[1] Note (as explained in the comments) this would usually only happen when the repo is brand-new ("pristine") or if no commits have been made. More technically, whenever there is no checkout or work-tree.

Just making it more clear :)

7 Comments

Yea it's more like deleting the created index itself. Good thing is that, I don't require to re-initialize git. Thanks!
Are sure it's a safe operation? I just did this (actually moved index out of way) and got all other files staged for deletion.
Actually, I was wondering what you meant by "pristine repo" (I don't feel lucky with google either).. So you meant an empty repo actually?
Ah, so you did mean an empty repo. Quite a specific case indeed:) the question doesn't suggest this scenario, can't see how this became the selected answer for @sarat's case. Thanks anyway.
@inger Agree. I had to assume that the OP had happened to have this exact situation - he doesn't specify it, but his description leaves the possibility. Anyways, I'm just sharing information, and can't influence the voting :(. Have added a word of warning to the answer text, in case it helps others in the future.
|
19

Use git reset HEAD to reset the index without removing files. (If you only want to reset a particular file in the index, you can use git reset HEAD -- /path/to/file to do so.)

The pipe operator, in a shell, takes the stdout of the process on the left and passes it as stdin to the process on the right. It's essentially the equivalent of:

$ proc1 > proc1.out $ proc2 < proc1.out $ rm proc1.out 

but instead it's $ proc1 | proc2, the second process can start getting data before the first is done outputting it, and there's no actual file involved.

6 Comments

but to how to use it with multiple files. I never have commited these files before.
Just type git reset HEAD without specifying anything else, and it will reset the entire index. You can then just re-add only the files you want.
I got the following error. I never committed these items before. $ git reset HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions
Try just git reset then, without the HEAD.
I already tried that I ended up in the following error. $ git reset fatal: Failed to resolve 'HEAD' as a valid ref.
|
12
git stash && git stash pop 

1 Comment

I would do 'git stash && git stash pop' so that the stash also gets deleted. 'apply' would leave the stash in the stash list.
7

If HEAD isn't set (i.e., you have no commits yet, but you don't want to just blow away .git because you've already set up other repo config you want to keep), you can also do

git rm -rf --cached . 

to unstage everything. This is effectively the same as sehe's solution, but avoids mucking with Git internals.

5 Comments

this actually tells Git to delete everything in the cached area.
The cache is also known as the staging area, so I'm not sure what you're getting at.
From sehe, rm .git/index is very dangerous - be sure to read the NOTE he has about a brand new repo! This is much safer for the other 99.999% of the time. I didn't read carefully and had to blow away my working copy and re-clone after doing rm .git/index on my working copy.
DO NOT use this command! It will change ALL project to the untracked state (including ones that were not staged). This is not a solution to the original question. The correct solution using the 'git rm' command is to ONLY specify the files you want unstaged: git rm -rf --cached <files you want to unstage>.
You should only use this command when you have a new repo with no commits yet (this is what "HEAD isn't set" means), but you don't want to just blow away .git because you've set up other repo config you want to keep. I've edited to clarify this.
6

Warning: do not use the following command unless you want to lose uncommitted work!

Using git reset has been explained, but you asked for an explanation of the piped commands as well, so here goes:

git ls-files -z | xargs -0 rm -f git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached 

The command git ls-files lists all files git knows about. The option -z imposes a specific format on them, the format expected by xargs -0, which then invokes rm -f on them, which means to remove them without checking for your approval.

In other words, "list all files git knows about and remove your local copy".

Then we get to git diff, which shows changes between different versions of items git knows about. Those can be changes between different trees, differences between local copies and remote copies, and so on.
As used here, it shows the unstaged changes; the files you have changed but haven't committed yet. The option --name-only means you want the (full) file names only and --diff-filter=D means you're interested in deleted files only. (Hey, didn't we just delete a bunch of stuff?) This then gets piped into the xargs -0 we saw before, which invokes git rm --cached on them, meaning that they get removed from the cache, while the working tree should be left alone — except that you've just removed all files from your working tree. Now they're removed from your index as well.

In other words, all changes, staged or unstaged, are gone, and your working tree is empty. Have a cry, checkout your files fresh from origin or remote, and redo your work. Curse the sadist who wrote these infernal lines; I have no clue whatsoever why anybody would want to do this.


TL;DR: you just hosed everything; start over and use git reset from now on.

Comments

3

I'm afraid that the first of those command lines unconditionally deleted from the working copy all the files that are in git's staging area. The second one unstaged all the files that were tracked but have now been deleted. Unfortunately this means that you will have lost any uncommitted modifications to those files.

If you want to get your working copy and index back to how they were at the last commit, you can (carefully) use the following command:

git reset --hard 

I say "carefully" since git reset --hard will obliterate uncommitted changes in your working copy and index. However, in this situation it sounds as if you just want to go back to the state at your last commit, and the uncommitted changes have been lost anyway.

Update: it sounds from your comments on Amber's answer that you haven't yet created any commits (since HEAD cannot be resolved), so this won't help, I'm afraid.

As for how those pipes work: git ls-files -z and git diff --name-only --diff-filter=D -z both output a list of file names separated with the byte 0. (This is useful, since, unlike newlines, 0 bytes are guaranteed not to occur in filenames on Unix-like systems.) The program xargs essentially builds command lines from its standard input, by default by taking lines from standard input and adding them to the end of the command line. The -0 option says to expect standard input to by separated by 0 bytes. xargs may invoke the command several times to use up all the parameters from standard input, making sure that the command line never becomes too long.

As a simple example, if you have a file called test.txt, with the following contents:

hello goodbye hello again 

... then the command xargs echo whatever < test.txt will invoke the command:

echo whatever hello goodbye hello again 

3 Comments

I never made any commits so it will say like can't resolve HEAD. What we do in such situations. Thanks a lot for explaining pipe in detail.
If you have just changed your git ignore and did git add --all to include a lot of files, DO NOT run git reset --hard to unstage them. THEY WILL BE DELETED!!
Uwaaahh!! Maybe you need to highlight the word "carefully". I just saw these three words "git reset --hard" and all my unstaged files are...fufff!! gone!!!!!
2

If you want to unstage all the changes use below command,

git reset --soft HEAD 

In the case you want to unstage changes and revert them from the working directory,

git reset --hard HEAD 

Comments

2

To remove changes from the staging area use the git restore --staged <filename> command. This action relocates the specified file back to your working directory, without altering its content.

To unstage all changes simultaneously use git restore --staged .

Reference - https://youtube.com/shorts/yFk7PPE1Z1A?si=xR7ZmCTBmF6pz04z

2 Comments

This is just repeating the solution from this answer: stackoverflow.com/a/62569232/2745495
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.