Git

How to Unstage a File in Git in Simple Steps

How to Unstage a File in Git in Simple Steps

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?

YouTube player

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.

  1. Run git status and find the file under “Changes to be committed”.
  2. Run git restore --staged index.html, swapping in your own path.
  3. Run git status again. The file now appears under “Changes not staged for commit”.
  4. Run git diff --staged and 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.

Why is GitHub the heart of open source?

Uncover GitHub statistics: developer community growth, repository trends, collaboration patterns, and the platform that powers modern software development.

Explore GitHub Data →

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.

Looking to sharpen your Git skills? Branching, merging, rebasing, and everything else you need - including git rebase, git stash, and commit workflows - is on one page in the Git Cheat Sheet.

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.css
  • git 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.

CommandReachRun from src/
git resetWhole repositoryClears staged files outside src/ too
git restore --staged .Current directory and belowLeaves staged files elsewhere alone
git restore --staged :/Whole repositorySame 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.

▶ GIT EXPLAINED

If you commit, branch, or merge code every day, it helps to know how Git came to be. This video covers how Linus Torvalds created Git in just 10 days after a license dispute and explains how its data model actually works.

Linus Torvalds Built Git in Days Out of Spite
Built in 10 Days Out of Spite. Git and its data model explained in plain language.

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:

  • y unstages this hunk
  • n keeps it staged
  • s splits it into smaller hunks
  • e lets you edit the hunk by hand
  • q quits

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.

SituationCommandReason
Git 2.23+, commits existgit restore --staged <file>Name states the job
Git older than 2.23git reset <file>Restore is missing
No commits yetgit reset <file>No HEAD to compare
Clear the whole indexgit resetOne short command
Stop tracking, keep on diskgit 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.

CommandTouchesEdits lost
git restore --staged --worktree <file>Index and working treeYes
git checkout -- <file>Working treeYes
git reset --hardIndex and working tree, all tracked filesYes
git reset --soft HEAD~1Branch pointer onlyNo
git reset HEAD~1Branch pointer and indexNo

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.

Bogdan Sandu

Stay sharp. Ship better code.

Every week: one curated article, one tool worth knowing, one tip you can use tomorrow. No noise, no padding.