Devpuff
Pricing
Log InStart Free
  1. Home
  2. Blog
  3. How to undo git add before committing
Tools

How to undo git add before committing

To undo a git add, git restore --staged unstages the file and keeps your edits. In a repo with no commits yet it fails, and git reset works.

By Max Arthur
Co-Founder & Content Marketer·September 25, 2026·8 Min read
White text reading 'How to undo git add' on a dark purple dotted background

To unstage a file you added by mistake:

git restore --staged file.txt     # one file
git restore --staged .            # everything

Your edits are not touched. Unstaging moves a file out of the list of things that will go into the next commit, and leaves the file on disk exactly as you left it. Nothing you typed is at risk.

The older command does the same job and still works everywhere:

git reset file.txt

There is one situation where restore fails and reset does not, covered below. Every output here came from a real repository on git 2.50.0.

The three places a change can be

Undoing git add is easy once you can see where a file currently sits. Git has three:

Place What it holds
Working directory The files on disk, as you edited them
Staging area (index) What will go into the next commit
Repository (HEAD) What is already committed

git add copies a change from the first to the second. Unstaging copies it back. The file on disk never moves in either direction, which is why this operation is safe.

Reading git status properly

git status --short prints two columns, and they are the whole story. The first column is the staging area; the second is the working directory.

Staging a modified file and a new file gives this:

M  a.txt
A  new.txt

M and A are in the left column, so both changes are staged. Now unstage the first:

git restore --staged a.txt
 M a.txt
A  new.txt

The M moved from the left column to the right. Same letter, different position, entirely different meaning: it went from "staged for commit" to "modified but not staged".

Unstage the second and it changes character:

git reset new.txt
 M a.txt
?? new.txt

new.txt becomes ??, untracked. It was never committed, so removing it from the staging area leaves git with no record of it at all. That is correct, and the file is still on disk.

Once you can read those two columns, most git confusion about "did that work" answers itself.

The case where restore fails

In a repository with no commits yet:

git init
echo x > f.txt
git add f.txt
git restore --staged f.txt
fatal: could not resolve HEAD

git restore --staged works by restoring the file's index entry to whatever HEAD says it should be. In a repository with no commits, HEAD points at a branch that does not exist yet, so there is nothing to restore to.

git reset handles it:

git reset f.txt
?? f.txt

This is the entire practical reason to still know reset. Everywhere else the two are interchangeable for this task, and restore is clearer because its name says what it does.

The three commands and when to use each

Command Use for
git restore --staged <file> The normal case, git 2.23 and later
git reset <file> Same job, works with no commits yet, works on old git
git rm --cached <file> A newly added file you want git to forget entirely

git rm --cached deserves care because the name sounds destructive and is not, in this form. It removes the file from the staging area and from tracking, and leaves it on disk. Without --cached it deletes the file too, which is a very different command separated by one flag.

Its real use is untracking something you committed by accident, such as a .env file, which is covered in what to put in .gitignore.

Why the staging area exists

Undoing an add feels like a chore until the staging area stops being a step between editing and committing, and starts being the thing that lets you choose what a commit contains.

A working session usually produces several unrelated changes: the feature, a typo you noticed, a stray console.log, a config tweak. Committing all of that together produces a commit nobody can review and nobody can revert cleanly.

The staging area lets you separate them without undoing any work:

git add -p                 # choose hunks for the first commit
git commit -m "add search filters"
git add -p                 # choose the next set
git commit -m "fix typo in header"

git add -p walks through each change and asks whether to stage it: y to stage, n to skip, s to split a hunk into smaller pieces, q to stop. Ten minutes with it is the fastest way to understand what staging is for.

Once you are staging in pieces, the need to undo an add mostly disappears, because you are choosing deliberately rather than running git add . and correcting afterwards.

Bulk cases

The whole staging area at once:

git restore --staged .
git reset                  # same thing, older syntax

git reset with no arguments and no paths unstages everything. It does not move the branch or touch your files, which surprises people who associate reset with danger. The dangerous forms need a commit argument or --hard, as covered in reset versus revert.

A directory:

git restore --staged src/

Everything except one file, which has no direct syntax. Unstage all, then re-add the one you want:

git restore --staged .
git add keep-this.txt

What none of these do

They do not discard your edits. Every command on this page moves a change between the staging area and the working directory. If you actually want to throw away the edit:

git restore file.txt          # discard unstaged changes to one file

That one is destructive, and it is one character different in spirit from the version with --staged. Read the flag before running it, because there is no undo: uncommitted work that git has never seen is the one thing the reflog cannot recover.

A safer habit when you are unsure is to stash rather than discard:

git stash

That parks the changes where you can get them back, and is covered in how to use git stash.

They do not undo a commit. If you have already committed, unstaging does nothing useful, and you want undoing your last commit instead.

Unstaging part of a file

Sometimes you staged a whole file and only wanted some of it. Rather than unstaging everything and re-adding carefully, unstage interactively:

git restore --staged -p file.txt

Git walks you through each hunk and asks whether to unstage it. The same -p works on git add, and staging in hunks is the habit that removes most of the need to undo an add at all.

For a quick look at exactly what is currently staged, before you decide:

git diff --staged

Plain git diff shows unstaged changes; --staged shows what is about to be committed. Comparing the two is the fastest way to see whether the split is what you intended.

The shortcut that skips staging

Worth knowing, because it explains why some people rarely need any of this:

git commit -a -m "message"

-a stages every tracked file that has changed and commits in one step. It does not add new files, which is the part people forget: a brand-new file still needs an explicit git add.

It is convenient for small, focused changes where everything modified belongs in the same commit. It is the wrong default for anything larger, because it removes exactly the choice that the staging area exists to give you, and it is how unrelated changes end up bundled together.

The reasonable position is to know it, use it for one-line fixes, and stage deliberately for anything else.

Three common mistakes

Reaching for git reset --hard to unstage. It works, in the sense that the file is no longer staged, and it also throws away your edits. The flagless git reset <file> is what you wanted, and the difference is the entire contents of your afternoon.

Confusing git restore with git restore --staged. One discards your changes, the other unstages them. Same command, opposite risk profile, separated by a flag. If you are unsure which you are about to run, git diff first and see what you would be losing.

Assuming unstaging removes the file. For a file that was already tracked, unstaging just moves the change back to the working directory. For a newly added file it becomes untracked, which looks like it vanished from git's view, and the file is still on disk either way. Nothing on this page deletes anything.

Quick reference

git restore --staged <file>   # unstage, keep edits
git restore --staged .        # unstage everything
git reset <file>              # same, and works with no commits yet
git rm --cached <file>        # unstage AND untrack, keep on disk
git diff --staged             # what is staged right now
git restore <file>            # DISCARD edits (destructive)

Want to practise staging and unstaging where nothing is at risk? Work through Git basics in a real repository in the browser.

Keep reading

More from the blog

White text reading 'Objects are not valid as a React child' on a dark purple dotted background
October 7, 2026·7 min readTools

Objects are not valid as a React child: what to render

Objects are not valid as a React child, and React tells you which one by listing its keys. In React 19 the promise version throws a different error.

Read more
White text reading 'How to fix npm install errors' on a dark purple dotted background
October 6, 2026·8 min readTools

npm install errors: read the code, not the stack

Every npm ERR code names one cause. ERESOLVE, E404, EJSONPARSE and the rest, with what each one means, measured against real installs.

Read more
{ }
✦

Ready to write some code?

Put this into practice - start your first free lesson. No setup, no credit card.

Start learning free
Devpuff

Learn to code by doing. One tiny, playful lesson at a time.

Learn
ProgramsCoursesPricing
Company
AboutBlogResourcesAffiliates
Support
Help CenterContactStatus
Programs
Frontend DevelopmentFull-Stack DevelopmentReact DeveloperPython Developer
Courses
Advanced ReactAsync JavaScriptAsync PythonCSS BasicsCSS LayoutDSA Basics
Learn to Code
Learn JavaScriptLearn PythonLearn SQLLearn HTMLLearn CSSLearn ReactBrowse All Topics
Platform Comparisons
Devpuff vs CodecademyDevpuff vs Mimo
© 2026 Devpuff. All rights reserved.Privacy PolicyTerms and ConditionsCookies PolicyRefund Policy
Devpuff vs Sololearn
Devpuff vs freeCodeCamp
Read All Comparisons