GitUnstaging Files

Unstaging Files

Unstaging is the opposite of git add. You staged a file (it is now in the index, ready for the next commit), and you want it out of the index again — but you do not want to lose your edits. Unstaging moves the index entry back to whatever HEAD says, while your working-tree file keeps your changes.

What “unstage” means in the three-trees picture

Only the index changes

Text
Working dir     Index (staging)     Repository (HEAD)
   modified  ───▶  modified           clean
                       │
                       │  git restore --staged file
                       ▼
   modified           clean              clean

The file is still 'modified' in your working tree —
just no longer queued for the next commit.
Modern: git restore --staged

The recommended way (Git 2.23+)

Bash
# Unstage one file
git restore --staged src/util.js

# Several files
git restore --staged src/util.js src/helpers.js

# A whole directory
git restore --staged src/

# Everything currently staged
git restore --staged .
Legacy: git reset

Before git restore existed, the way to unstage was a path-mode git reset. It still works — and you will see it in plenty of tutorials and git status hints from older Git versions.

The pre-2.23 way (still works)

Bash
# Unstage one file
git reset HEAD src/util.js
# HEAD is the default, so this also works:
git reset src/util.js

# Unstage everything
git reset
Why both spellings still exist
`git restore --staged` was introduced to give unstaging its own clear command instead of overloading `reset`. The old form is kept for backward compatibility — both produce identical results.
Partial unstage with -p

Just like git add -p lets you stage selected chunks, the patch mode of git restore --staged lets you unstage selected chunks. Useful when you staged a big diff and want to keep some of it in the index.

Interactive unstage

Bash
git restore --staged -p src/util.js
# Unstage this hunk [y,n,q,a,d,/,j,J,g,e,?]?
#   y - unstage this hunk
#   n - keep this hunk staged
#   s - split the hunk into smaller pieces
#   q - quit
The classic mistake: git add .

The five-second recovery

Bash
git add .                       # oops, staged everything including secrets.env

git restore --staged .          # back to nothing staged
git status                      # confirm

# Now selectively add what you actually wanted
git add src/feature.js src/feature.test.js
Unstage vs discard — do not confuse them

Goal

Command

Effect on your edits

Unstage (keep edits)

git restore --staged <file>

Edits remain in the working tree

Unstage AND throw away edits

git restore --staged --worktree <file>

Edits are permanently lost

Throw away unstaged edits only

git restore <file>

Edits in working tree are lost

Remove a file from staging that was new/untracked

git rm --cached <file>

File becomes untracked; copy stays on disk

Unstaging a brand-new (never-committed) file

If you git add a file that was previously untracked and want to undo just the staging, the same commands work. The file becomes untracked again; the file on disk is left alone.

Untrack what you just added

Bash
echo "secret" > secrets.env
git add secrets.env             # accidentally staged

git restore --staged secrets.env
git status
#   Untracked files: secrets.env

# Now add it to .gitignore so it does not happen again
echo "secrets.env" >> .gitignore
What git status tells you

Status hints point you to the right command

Bash
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   src/util.js

# That parenthesised hint IS the official answer.
# Copy it, run it, done.
Tip
Get into the habit of running `git status` between staging and committing. Two seconds of looking saves you the painful “whoops, I committed an .env file” moment that almost everyone has had at least once.