| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | git 2.52.0 |
| Applies to | Any host with Git installed |
| Privilege | Normal user |
| Scope | Unstage command reference before commit — git restore --staged, git reset HEAD, bare git reset, directory pathspecs, and git rm --cached. Covers staged deletions and repos with no commits yet. Not a step-by-step undo git add walkthrough or a discard/reset tutorial. |
| Related guides | Git undo add Git restore examples Git reset examples Remove file from tracking Git diff examples |
Unstaging removes paths from Git's staging area (the index) without touching the file content on disk. You use it after git add when a path should not appear in the next commit yet.
This page is the command reference — syntax, flags, pathspecs, and comparisons. If you accidentally ran git add and want the smallest fix with git status -sb explained line by line, start with Git undo add.
Unstage command quick reference
| Goal | Command |
|---|---|
| Unstage one tracked file | git restore --staged file |
| Same job (older/common alternative) | git reset HEAD file |
| Unstage several paths | git restore --staged file1 file2 |
| Unstage everything under a folder | git restore --staged src/ |
| Unstage all staged paths in the repo | git reset |
| Unstage under the current directory only | git restore --staged . (run from repo root to cover the whole tree) |
| Unstage before the first commit | git reset path |
| Unstage a staged deletion | git restore --staged file |
| Unstage a newly added file | git restore --staged file |
| Stop tracking while keeping the file locally | git rm --cached file |
None of these commands delete untracked files from your working tree by themselves.
Check what is staged
Before you pick a command, confirm which column in git status -sb holds the staging signal. The first column is the index; the second is the working tree.
git status -sb## main
M app.txt
A config.env
M notes.txt
M src/helper.pyM or A in column one means the path is staged. config.env is a new file staged for the next commit; the others are modifications to tracked files.
To read the staged diff itself:
git diff --stagedThat shows what would land in the commit if you ran git commit right now. For a deeper diff walkthrough, see Git diff examples.
Unstage one file with git restore --staged
git restore --staged resets the index entry for one path toward HEAD. Your edits stay on disk.
With app.txt staged among other paths, remove only that file from the index:
git restore --staged app.txtConfirm column one no longer marks app.txt:
git status -sb## main
M app.txt
A config.env
M notes.txt
M src/helper.pyThe leading space before M on app.txt means it is modified locally but not staged. The other paths are still staged.
Unstage one file with git reset HEAD
git reset HEAD file is the traditional form. On a repository with commits, it unstages the same way as git restore --staged.
Stage app.txt again so you can compare the reset spelling:
git add app.txtRun the older reset form:
git reset HEAD app.txtUnstaged changes after reset:
M app.txtGit prints which paths moved out of the index. Short status should match the restore example:
git status -sb## main
M app.txt
A config.env
M notes.txt
M src/helper.pyPrefer git restore --staged on Git 2.23 and later because the command name states the intent. git reset HEAD is not deprecated though. Git still documents pathspec reset as the opposite of git add, so keep using it in existing scripts and expect it in older docs.
Unstage multiple files or a directory
List every path in one command when you need several files unstaged but not the whole repo:
git restore --staged app.txt notes.txtDirectory pathspecs work too. After staging src/helper.py with the rest of the tree, unstage the whole folder:
git restore --staged src/Ask status which paths still sit in column one:
git status -sb## main
M app.txt
A config.env
M notes.txt
M src/helper.pyOnly paths under src/ left the index. Files outside that directory stay staged.
Unstage everything
Two common spellings cover "clear the entire staging area."
Bare git reset (no path) unstages every staged change in the repository:
git resetEvery staged path should now show a space in the first column:
git status -sb## main
M app.txt
M config.env
M notes.txt
M src/helper.pyEvery path now shows a space in column one. Your file edits remain.
git restore --staged . unstages paths that match . — the current directory and everything below it. Run it from the repository root when you mean the whole project:
git add .From the repository root, . matches the whole tree:
git restore --staged .Both git reset and git restore --staged . keep working-tree content. The difference is scope: bare reset always targets the full index, while . follows your current directory. For the accidental git add . scenario with status reading first, see Git undo add.
Unstage a new file with git rm --cached
A newly added file can leave the index in two ways.
git restore --staged config.env moves a staged new file back to untracked — same as unstaging a modification.
git rm --cached config.env also removes the path from the index but is the usual choice when you want to stop tracking a file that should stay on disk. Stage the file again to see the cached removal:
git add config.envThe cached form removes the index entry but leaves the file on disk:
git rm --cached config.envrm 'config.env'Untracked ?? in the last column confirms Git no longer tracks the path:
git status -sb## main
M app.txt
M notes.txt
M src/helper.py
?? config.env?? means Git no longer tracks config.env, but the file is still present locally. If the file was already tracked in an earlier commit, committing this staged removal drops it from future versions of the repository while your local copy stays on disk. That is the real difference from a simple unstage, which leaves the path tracked — see remove file from tracking.
Unstage a staged deletion
When you git rm a tracked file or stage a manual delete, column one shows D. Unstaging removes the deletion from the index without restoring the file on disk.
A staged delete of the tracked file tracked-del.txt looks like this in short status:
git status -sb## main
D tracked-del.txtUnstage the deletion:
git restore --staged tracked-del.txtCheck where the D sits now:
git status -sb## main
D tracked-del.txtThe space before D means the delete is no longer staged. The file is still missing on disk until you run git restore tracked-del.txt to recover it from HEAD.
Compare git restore --staged, git reset, and git rm --cached
These three names show up together in unstage searches, but they answer different questions:
| Command | What it changes | Typical use |
|---|---|---|
git restore --staged path |
Index only — working tree untouched | Reverse git add on a path you still want tracked |
git reset HEAD path or bare git reset |
Index toward HEAD (and more modes if you add flags) |
Same unstage result on repos with history; bare form clears all staged paths |
git rm --cached path |
Removes path from index; file stays on disk | Stop tracking while keeping the file locally |
git reset --hard and git restore --worktree discard working-tree content. They are not unstage commands — see Git discard changes and Git reset examples.
After git commit
Unstage commands apply only while changes sit in the index waiting for a commit. Once git commit finishes, the snapshot is in history and there is nothing left to unstage.
Undo or rewrite that commit with git reset or git revert instead — see Git reset examples and revert to previous commit.
Before the first commit
git restore --staged needs a HEAD commit to compare against. In a freshly initialized repository, it fails:
Start a repository with no commits yet:
git init -b mainStage a new file in that empty repo:
printf 'new\n' > fresh.txt && git add fresh.txtgit restore --staged fails because there is no HEAD commit to compare against:
git restore --staged fresh.txtfatal: could not resolve HEADUse git reset with a path instead:
git reset fresh.txtThe file should return to untracked status:
git status -sb## No commits yet on main
?? fresh.txtAfter your first commit, git restore --staged works normally.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
fatal: could not resolve HEAD |
No commits in the repository yet | git reset path instead of git restore --staged |
| Command runs but nothing changes | Path was not staged, or typo in the path | Run git status -sb and match the path exactly |
git reset did not help |
Changes were already committed | Use reset or revert on the commit, not unstage commands |
File still shows M after unstage |
Expected — only column one cleared | Edits remain until you commit or discard them |
| Wanted to discard local edits, not just unstage | Unstaging never touches the working tree | git restore file rewrites the working file from the index |
| Wanted to discard both the staged and the unstaged copy | Two places hold the change: index and working tree | git restore --source=HEAD --staged --worktree file — see Git discard changes |
Used git rm --cached by mistake |
Goal was only to reverse git add |
git restore --staged file when the file should stay tracked |
| Staged delete unstaged but file still missing | Unstage only removed the index deletion | git restore file to recover content from HEAD |
References
Summary
Unstaging clears paths from Git's index while leaving your working-tree edits intact. git restore --staged path is the modern default for one file, a list of paths, or a directory pathspec. git reset HEAD path and bare git reset remain valid — especially in scripts — and bare git reset is the fastest way to empty the entire staging area.
git rm --cached belongs in a different column: it stops tracking a file while keeping it on disk, not merely reversing an accidental git add. Staged deletions use the same unstage command as modifications; recovering the file content is a separate git restore step afterward.
For a mistake-driven walkthrough that reads git status -sb before each fix, use Git undo add. To discard edits or rewrite commits after the staging step is past, see Git discard changes and Git reset examples.

