To undo git add for one file before you commit, run:
git restore --staged app.txt
To unstage everything you added (for example after git add .), run git reset with no arguments. Both commands only change what is staged. Your edits in the working folder stay exactly as they are, so nothing is lost.
Quick reference
| You want to… | Command |
|---|---|
| Unstage one file | git restore --staged <file> |
| Unstage all files | git restore --staged . or git reset |
| Unstage in a repo with no commits yet | git reset <file> or git rm --cached <file> |
| Older syntax (still works) | git reset HEAD -- <file> |
Undo git add and the commit | See Git undo last commit |
I tested all of these with the Git that ships with the Xcode Command Line Tools:
git version 2.39.5 (Apple Git-154)
git restore has been in Git since 2.23, so Apple’s Git has it. You do not need Homebrew Git for anything here.
Unstage one file with git restore —staged
My test repo had one commit. Then I edited app.txt, created .env and notes.txt, and ran git add . by mistake. git status even prints the undo command for you:
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: .env
modified: app.txt
new file: notes.txt
To take only .env out of the next commit:
git restore --staged .env
git status -s
M app.txt
A notes.txt
?? .env
.env went back to untracked (??). The other two files are still staged. The file itself is untouched on disk.
Unstage everything (undo git add .)
You have two equivalent options:
git restore --staged .
or the shorter classic:
git reset
Here is what git reset printed in my repo:
Unstaged changes after reset:
M app.txt
It only lists files Git already tracked. The new files (.env, notes.txt) are unstaged too, they just aren’t mentioned. Check with git status -s:
M app.txt
?? .env
?? notes.txt
Notice the M moved from the first column (staged) to the second column (modified, not staged). Add -q (git reset -q) if you don’t want the message.
Plain git reset is safe. It defaults to --mixed, which never touches your files. Only git reset --hard throws away edits, so don’t add that flag here.
Gotcha: before the first commit, git restore —staged fails
This one tripped me up. In a brand-new repo with no commits, git restore --staged does not work:
git init
echo hi > a.txt
git add a.txt
git restore --staged a.txt
fatal: could not resolve HEAD
There is no commit yet, so there is nothing to “restore” from. Git hints at the right command in this case. Look at the status text — it changes when there are no commits:
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: a.txt
Both of these worked in the empty repo:
git reset a.txt
git rm --cached a.txt
git reset a.txt exited with status 0 and left the file untracked (?? a.txt). git rm --cached a.txt printed rm 'a.txt' and did the same.
Don’t use git rm —cached on files that are already committed
git rm --cached is often suggested as “the” way to undo git add. That is only true for new files. On a file that is already in a commit, it does something very different: it stages a deletion.
git rm --cached app.txt
git status -s
D app.txt
?? app.txt
If you commit now, app.txt is removed from the repo for everyone (your local copy stays, as untracked). That is the right move when you want Git to stop tracking a file, but it is not “undo add”. If you ran it by accident, git restore --staged app.txt puts things back:
M app.txt
What happens if you edited the file again after git add
Say you stage app.txt, then keep editing it. Status shows MM: one version staged, newer changes on top.
MM app.txt
Running git restore --staged app.txt does not roll your file back to the staged version. It keeps the newest content on disk and only empties the staging area:
M app.txt
line one
line two
line three
All three lines are still in the file. Nothing you typed after git add is lost.
Insight: the staged copy stays inside .git (and can be recovered)
When you run git add, Git immediately saves a copy of the file inside .git/objects. Unstaging does not delete that copy. I tested this by staging a file, overwriting it, and then unstaging:
echo "draft v1 important" > draft.txt
git add draft.txt
echo "oops" > draft.txt
git restore --staged draft.txt
git fsck --lost-found
dangling blob e5c5c5583f49a34e86ce622b59363df99e09d4c6
dangling blob 8ba3a16384aacc37d01564b28401755ce8053f51
dangling blob 587cd42914ec039fde0c0037e9e5c42d8f20d017
dangling blob db3dad9f594eeb894b12ea325151f1a5c2cfa942
git fsck --lost-found writes every orphaned copy to .git/lost-found/other/. One of them held the lost text:
.git/lost-found/other/587cd42914ec039fde0c0037e9e5c42d8f20d017:
draft v1 important
So if you staged a version and then lost it in your editor, you can usually get it back this way.
The flip side: the .env file I staged by mistake was also there, as secret=1. Unstaging does not wipe it from .git. It is not pushed anywhere (dangling objects aren’t sent on git push), but if you zip or copy the whole project folder, it goes along. Git’s automatic cleanup only prunes them once they are older than two weeks (the default gc.pruneExpire), and only when that cleanup actually runs. To remove them now:
git gc --prune=now
After that, git cat-file -t db3dad9f returned fatal: Not a valid object name, and git fsck --lost-found found nothing. If you ever need to clean secrets out of commits you already pushed, that is a bigger job than this.
Adding a file to .gitignore does not unstage it
Another thing I checked: if you staged .env and then add it to .gitignore, it stays staged.
A .env
?? .gitignore
.gitignore only affects untracked files. You still need git restore --staged .env (or git rm --cached .env once it’s committed). If you set up .env files often, our guide on creating files in Terminal shows how hidden dotfiles behave in Finder too.
Common questions
Does undoing git add delete my changes?
No. git restore --staged, git reset and git reset HEAD -- <file> only change the staging area. In every test above, the file on disk was unchanged afterward.
What’s the difference between git restore —staged and git reset?
For unstaging they do the same thing. git restore --staged is the newer, clearer command that Git’s own status hints use. git reset <file> is older and works even before the first commit, where restore --staged fails with fatal: could not resolve HEAD.
How do I unstage only part of a file?
Use git restore --staged -p <file> (or git reset -p <file>). Git shows each staged chunk and asks y or n. I did not run the interactive prompt for this guide, but it is the mirror of git add -p.
I already committed. How do I undo git add now?
Then the add is part of a commit. Run git reset --soft HEAD~1 to undo the commit and keep everything staged, then unstage what you want. The full walkthrough is in Git undo last commit.
How do I see what is staged before I commit?
git diff --cached --name-only lists staged files. In my repo it printed app.txt and notes.txt. Drop --name-only to see the actual changes.