Most of the time, unstaging a file in Git is one command: git restore –staged <file>. It pulls the file out of the index and leaves your edits sitting in the working tree. You need Git 2.23 or later for it.
That version added git restore in August 2019 (GitHub Blog). On anything older, git reset <file> does the same job.
There is one spot where the newer command fails, and it catches people out. In a repository with no commits yet, restore stops with “fatal: could not resolve HEAD”, because it rebuilds the index from HEAD and there isn’t one.
A Git mailing list report from May 2020 documents the failure. git reset <file> works fine in that state.
How Do You Unstage a File in Git?

Run git restore --staged <file> and Git removes the file from the index. Whatever you changed stays in the working directory.
Git 2.23 is the minimum, which shipped in August 2019 (GitHub Blog). Older versions tell you restore is not a git command, and git reset covers those.
- Run
git statusand find the file under “Changes to be committed”. - Run
git restore --staged index.html, swapping in your own path. - Run
git statusagain. The file now appears under “Changes not staged for commit”. - Run
git diff --stagedand confirm the file is gone from the staged diff.
Honestly, you don’t have to memorize any of this. The output of git status prints the command as a hint right under “Changes to be committed”.
What Happens to Your Edits
Nothing. Git’s staging area sits between the last commit and your files, and the command rewrites only that middle layer.
HEAD is the last commit on the current branch, and it’s where the restore pulls from. The index holds the staged snapshot and is the only thing that changes. Your working tree, meaning the files on disk, never gets touched by --staged.
By default, --staged restores the index from HEAD, according to the git restore manual. Leave the flag off and the command does something quite different. It overwrites the file on disk with the index copy.
How Does git reset Unstage a File on Older Git Versions?
git reset HEAD <file> does the same thing as git restore --staged and runs on Git versions older than 2.23. The git reset manual states the equivalence directly: with a path, reset is git restore --staged under another name.
git reset HEAD <file>git reset -- <file>git reset <file>
Each form gives the same result because HEAD is the default target. Add the -- separator when a file name could be read as a branch or a commit.
The default mode is mixed, so your files stay exactly as they are. Per the git reset manual, the path form updates only the index, without touching HEAD or your working tree files. Git then lists whatever still carries unstaged edits.
Git’s reset command also moves HEAD when you hand it a commit instead of a path. For unstaging, stick to the path form.
How to Unstage Multiple Files, a Folder, All Files or a Single Hunk
The command reaches as far as the pathspec you give it. A list of files, a folder, a glob or one hunk inside a file all work.
Unstaging Several Files and Folders
List the paths one after another, or point at a folder and Git applies the pathspec to everything underneath it.
git restore --staged a.js b.cssgit restore --staged src/git restore --staged "*.log"
Quote the glob so the shell leaves it alone and Git matches the pattern itself.
Unstaging Everything
git reset and git restore --staged . look interchangeable. They aren’t, and you notice the difference the first time you run them from a subfolder.
| Command | Reach | Run from src/ |
|---|---|---|
git reset | Whole repository | Clears staged files outside src/ too |
git restore --staged . | Current directory and below | Leaves staged files elsewhere alone |
git restore --staged :/ | Whole repository | Same reach as git reset |
From the repository root they all behave the same. Anywhere else, the dot limits things to the current directory, since that’s simply what a pathspec of . means.
Unstaging One Hunk
Use git restore --staged -p <file> to unstage part of a file. Git steps through the staged hunks and asks what to do with each one.
Patch mode is the same interface git add uses when you stage hunks one at a time, and the git reset manual describes git reset -p as the opposite of git add -p. The prompt answers you will actually use:
yunstages this hunknkeeps it stagedssplits it into smaller hunkselets you edit the hunk by handqquits
Splitting only works when unchanged lines separate the changes. Adjacent changes stay in one hunk, and e is your fallback.
How to Unstage a New File or a File Before the First Commit
In a repository with no commits, use git reset <file>. The default git restore --staged fails there with “fatal: could not resolve HEAD”.
Newly Added Files in a Repository With History
git restore --staged works on a new file as long as one commit exists. HEAD holds no copy of the file, so Git drops the index entry and the file goes back to “Untracked files”.
The file stays on disk the whole time.
Repositories With No Commits Yet
Restore compares the index to HEAD. A fresh repository has no commit on the branch, so HEAD doesn’t resolve and Git exits with status 128.
A bug report on the Git mailing list described the failure in May 2020 on versions 2.26.2 and 2.27.0-rc1. A September 2026 issue in the ktsu GitIntegration repository reproduces it on Git 2.23 and later.
Two commands get you out of that state. git reset <file> drops the index entry without needing a commit. git rm --cached <file> is what the status hint suggests in a no-commit repository (Sentry). Both leave the file untouched on disk.
When git rm –cached Backfires
On a file Git already tracks, the same command stages a deletion. The git rm command defines --cached as removing paths from the index only, so the next commit records the file as deleted from the repository.
A new file with no history unstages cleanly. A tracked file gets a staged deletion, though it stays on your disk. If you hit that by accident, git reset -- <file> removes the staged deletion and puts the file back in the index.
Which Unstage Command Should You Use?
Use git restore --staged on Git 2.23 or later when at least one commit exists, and git reset everywhere else. Keep git rm --cached for stopping tracking, not for undoing a git add.
| Situation | Command | Reason |
|---|---|---|
| Git 2.23+, commits exist | git restore --staged <file> | Name states the job |
| Git older than 2.23 | git reset <file> | Restore is missing |
| No commits yet | git reset <file> | No HEAD to compare |
| Clear the whole index | git reset | One short command |
| Stop tracking, keep on disk | git rm --cached <file> | Changes what Git tracks |
The restore form reads clearly because the flag names what happens, and it takes -p for hunk-level control. Its only real weakness is the empty repository.
Reset runs on every version and on an empty repository, and a bare git reset clears the index in one step. The catch is that the same word also moves HEAD, and in hard mode it overwrites files.
The cached form is the odd one out. It removes a file from tracking while the file stays put, but it needs a follow-up commit and an ignore rule to keep the file untracked.
The sources agree on the result and split on teaching order. The git reset manual calls the path form equivalent to the restore form, yet GitLab’s archived docs for versions 16.1 and 16.7 still lead with git reset HEAD, while TheServerSide recommends only restore.
My pick is restore whenever both work. Reset has a wider reach, and git restore --staged cannot touch HEAD or your files by accident.
The cached form earns its place for local config files and build output. Add the path to your .gitignore file first, or the next git add . stages it again.
Which Look-Alike Commands Discard Your Changes?
A handful of commands sit close to unstaging in muscle memory, and some of them destroy edits. Unstaging itself never does.
| Command | Touches | Edits lost |
|---|---|---|
git restore --staged --worktree <file> | Index and working tree | Yes |
git checkout -- <file> | Working tree | Yes |
git reset --hard | Index and working tree, all tracked files | Yes |
git reset --soft HEAD~1 | Branch pointer only | No |
git reset HEAD~1 | Branch pointer and index | No |
Edits that were never staged or committed leave nothing for Git to bring back.
Before Git 2.23, git checkout with a path was the usual way to overwrite a file from the index, and the form still runs. The restore manual describes the combined --source=HEAD --staged --worktree call as the same as using git checkout, which in this case means git checkout HEAD -- <file>.
Unstaging and uncommitting are different jobs. A commit that already exists needs another route. Per the git reset manual, --soft leaves the index and working tree alone, while the default mixed mode updates the index so nothing stays staged.
One source blurs the two. GitLab’s archived docs (version 16.7) put a line about unstaging the last three commits under file unstaging, written as git reset HEAD^3.
In Git’s revision syntax, HEAD^3 is the third parent of a merge commit. Three commits back is HEAD~3.
When the real goal is to set work aside, git stash beats any reset. According to the git stash manual, git stash push --staged sets aside only what is staged.
A plain stash skips untracked files. Add --include-untracked to take them along.
Can You Unstage a File in VS Code, GitHub Desktop or Git GUI?
Yes. All of them unstage a file with one click, and VS Code and GitHub Desktop also reach individual lines.
VS Code
Open the Source Control view with Ctrl+Shift+G on Windows and Linux. In VS Code, hover the file under Staged Changes and select the minus icon, or right-click it and choose Unstage Changes.
To unstage only some lines, open the file’s diff and use the Unstage button in the gutter next to your selection (VS Code documentation).
A file with both staged and unstaged edits shows up in both groups at once, which looks odd the first time.
GitHub Desktop
Uncheck a file in the Changes list to unstage the whole thing. For part of a file, click the changed lines until the blue highlight disappears.
The app has no separate staged list, so the checkbox state is the staging state. Before you commit in GitHub Desktop, check which files are still ticked, and glance at the History tab afterwards to confirm the commit holds only what you meant.
Git GUI
Select the file in the Staged Changes pane, then choose Unstage From Commit in the Commit menu. Clicking the file’s icon instead of its name does the same.
Ctrl+U unstages the selected file from the keyboard. Git for Windows issue 1012 records the shortcut for Git GUI 0.21.
Common Questions About Unstaging a File in Git
How do you unstage a deleted file?
Run git restore --staged <file>, the same command used for edits. The staged deletion leaves the index, but the file stays missing from disk until you run git restore <file> to bring it back from HEAD.
What is the difference between git diff –staged and git diff –cached?
None. --staged is a synonym for --cached, and both show the changes in the index compared with the last commit.
How do you remove a file from the last commit?
Unstaging cannot reach a commit that already exists. Run git reset --soft HEAD~1 to undo the commit while keeping everything staged, unstage the file with git restore --staged <file>, then commit again.
If the commit is already pushed, rewriting it changes shared history.
Can you stage a file again after unstaging it?
Yes. Run git add <file> and the file returns to the index with its current working tree content, including any edits made after the unstage.
Keeping the Wrong Files Out of the Index
Unstaging a file in Git repairs a staging mistake, and naming each path in git add prevents most of those mistakes. A bare git add . stages everything under the current directory, including the local config file you left out on purpose.
Staging by path or with git add -p is the first habit worth building. Running git diff --staged before every commit catches whatever slipped through. For files that never belong in the repository at all, an ignore rule settles the problem for good.
Ignore rules have a limit, though: they never apply to a file Git already tracks. That file has to leave the index first.
The price of this routine is speed, since typing paths takes longer than one dot.
Once the index holds only the intended files, the next step is understanding what a git commit records from it.
- MongoDB Cheat Sheet - October 20, 2026
- Adding AI Video Generation to a Software Product: Architecture, Cost Guardrails and QA - October 20, 2026
- Show Hidden Characters, Spaces, and Line Endings in Notepad++ - October 19, 2026




