In Part 1 of our Git undo series, we showed how to fix mistakes that are not yet tracked by git, also known as your working directory. But what happens when you have already executed the git add
command and git is now tracking your changes and then you realized that you have made a mistake. In this blog post, we will cover how to undo staged changes in git.
In particular, we will cover the following most common undo scenarios:
- You ran
git add .
to quickly stage everything, only to realize that you have included a temporary debug file, build artifacts, or a sensitive credential. - You staged changes for a feature branch, but then remembered that you wanted to split a large change into two smaller, more focused commits.
- You accidentally added a file that should be ignored by Git altogether, and now it is sitting in your staging area, waiting to be committed.
Do not worry! Just because changes are staged and getting tracked by git, it does not mean they cannot be undone. Git provides straightforward ways to “unstage” these changes, moving them back to your working directory where you can modify them further or discard them entirely.
Let us explore how to undo changes from the Git Staging Area. But before that, please complete the initial setup as this is a continuation from the previous blog.
Scenario 1: How to Unstage Changes from a Single File?
This is perhaps the most frequently needed solution when working with the staging area. You have added a file, or specific changes within a file, but now you want to remove it from staging before committing.
Question: How do I unstage changes from a single specific file, moving them back to the working directory?
Answer: Use git restore --staged <file>
(recommended for modern Git) or git reset HEAD <file>
(for older Git versions).
Code:
# ----------------------------------
# Unstage Changes from a Single File
# ----------------------------------
# Step 1: Make some changes and stage them
echo "line 1" > file1.txt &&
echo "line 2" > file2.txt
# Step 2: Stage the changes using git add command
git add file1.txt file2.txt
# Step 3: Check the status
git status
# Output:
# On branch main
# Changes to be committed:
# (use "git restore --staged <file>..." to unstage)
# new file: file1.txt
# new file: file2.txt
# Observe: Both files are staged
# Step 4: Realize you want to unstage only file1.txt
git restore --staged file1.txt
# Or, for older Git versions
# git reset HEAD file1.txt
# Step 5: Check status again
git status
# Output:
# On branch main
# Changes to be committed:
# (use "git restore --staged <file>..." to unstage)
# new file: file2.txt
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
# file1.txt
Explanation:
git restore --staged
: This command is specifically designed for unstaging. The--staged
option tells Git to operate on the staging area. It takes the content from the last commit (HEAD) and puts it into the staging area, effectively “unstaging” your current changes for that file. The modified content of the file remains untouched in your working directory.git reset HEAD <file>
: In older Git versions,git reset
was used for this purpose.HEAD
refers to your current commit. By specifyingHEAD
and a file path, you are telling Git to reset the staging area for that file to match the state ofHEAD
. Your local changes are preserved in the working directory.
Notes/Warnings:
- Preserves Working Directory: Both commands do not discard your actual file modifications in the working directory. They only remove the changes from the staging area. The file will appear as “modified” (unstaged) in
git status
. - Selective Unstaging: This is perfect for when you have
git add
ed too much, and you want to selectively decide what goes into your next commit. Another alternative would be to use.gitignore
.
Scenario 2: How to Unstage ALL Changes?
If you have staged everything using the git add .
or git add *
command and then noticed that none of it should be committed yet, or you want to rethink what should go to your commit, you can unstage all changes.
Question: How do I unstage all changes that are currently in the staging area, moving them all back to the working directory?
Answer: Use git restore --staged .
(recommended) or git reset HEAD
.
Code:
# -------------------
# Unstage ALL Changes
# -------------------
# Step 1: Make some changes and stage them
echo "change A" > file1.txt &&
echo "change B" > file2.txt &&
mkdir new_folder && echo "new content" > new_folder/new_file.txt
# Step 2: Stage the changes using git add command
git add .
# Step 3: Check the status
git status
# Output:
# On branch main
# Changes to be committed:
# (use "git restore --staged <file>..." to unstage)
# new file: file1.txt
# new file: file2.txt
# new file: new_folder/new_file.txt
# Observe: See all new/modified files are staged
# Step 4: Unstage everything
git restore --staged .
# Or, for older Git versions
# git reset HEAD
# Step 5: Check status again
git status
# Output:
# On branch main
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
# file1.txt
# file2.txt
# new_folder/
#
# nothing added to commit but untracked files present (use "git add" to track)
# Observe: All changes are now 'untracked' (moved to working directory)
# Bonus:
# Step 6: Delete the unstaged files from working directory
git clean -fd
# Output:
# Removing file1.txt
# Removing file2.txt
# Removing new_folder/
# Step 7: Check status one last time
git status
# Output:
# On branch main
# nothing to commit, working tree clean
Explanation:
git restore --staged .
: Similar to the single-file version, the.
(dot) indicates the current directory, applying the un-staging operation to all tracked files.git reset HEAD
: Whengit reset HEAD
is used without a file path, it defaults to resetting the entire staging area to match theHEAD
commit.
Notes/Warnings:
- Preserves Working Directory: Just like with a single file, this command only unstages the changes. Your modifications remain in your working directory as “modified” (for tracked files) or “untracked” (for new files).
- New Files Remain Untracked: If you
git add
ed a new file, thengit restore --staged .
will unstage it, and it will revert to an “untracked” status in your working directory. You had then usegit clean
(as discussed in Part 1) if you want to permanently delete it.
Scenario 3: How to Remove a File from Staging Area But Keep it in the Working Directory?
You accidentally git add
ed a file that should never be part of your repository (e.g., a .env
file, an IDE configuration, or a large log file). You want to prevent it from being committed, but you do not want to delete the file from your local machine either. This is a common precursor to adding it to your .gitignore
file.
Question: How do I remove a file from the staging area without deleting it from my working directory?
Answer: Use git restore --staged <file>
(same as unstage) or git rm --cached <file>
.
Code:
# ---------------------------------------------------------------
# Remove a File from Staging But Keep it in the Working Directory
# ---------------------------------------------------------------
# Step 1: Create and stage a file to simulate accidental add
echo "MY_API_KEY=123" > .env && git add .env
# Step 2: Check the status
git status
# Output:
# On branch main
# Changes to be committed:
# (use "git restore --staged <file>..." to unstage)
# new file: .env
# Step 3: Remove .env from staging, but keep it locally
git rm --cached .env
# Alternative command to do the same thing
# git restore --staged .env
# Step 4: Check status again
git status
# Output:
# On branch main
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
# .env
#
# nothing added to commit but untracked files present (use "git add" to track)
Explanation:
git rm --cached <file>
: This command explicitly tells Git to “remove” the file from the index (staging area) while leaving the physical file untouched in your working directory. This is the ideal command when you want to add the file to.gitignore
immediately afterward.git restore --staged <file>
: While this also achieves the same result (unstaging the file and keeping it locally),git rm --cached
explicitly communicates the intent of removing it from tracking, which is often the goal when a file was accidentally added.
Notes/Warnings:
- Follow up with
.gitignore
: If you perform this action because a file should be ignored, immediately add its entry to your.gitignore
file to prevent it from being accidentally staged again in the future. - No Deletion: This command will not delete the file from your local file system.
Scenario 4: How to Remove a File from Staging AND Delete it from the Working Directory?
In some rare cases, you might have created a new file, added it to staging, and then decided you want to completely get rid of it – both from staging and from your local disk.
Question: How do I remove a file from the staging area AND delete it from my working directory?
Answer: Use git rm <file>
.
Code:
# -------------------------------------------------------------------
# Remove a File from Staging AND Delete it from the Working Directory
# -------------------------------------------------------------------
# Step 1: Create and stage a file
echo "hello world" > file1.txt && git add file1.txt
# Step 2: Check current status
git status
# Output:
# On branch main
# Changes to be committed:
# (use "git restore --staged <file>..." to unstage)
# new file: file1.txt
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
# .env
# Observe:
# .env is currently in working directory ready to staged
# file1.txt is currently in staging area, ready to get commited
# Step 3: Delete a file from staging area and working directory
git rm -f file1.txt
# Output:
# rm 'file1.txt'
# Step 4: Check the status once again
git status
# Output:
# On branch main
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
# .env
#
# nothing added to commit but untracked files present (use "git add" to track)
# Bonus:
# Step 5: Delete the unstaged files/dir from working directory
git clean -fd
# Output:
# Removing .env
# Step 6: Check status one last time
git status
# Output:
# On branch main
# nothing to commit, working tree clean
Explanation:
git rm -f <file>
: This command stages the deletion of the specified file and also deletes it from your working directory. It is effectively performingrm <file>
and thengit add <file>
(to stage the deletion). When you commit next, this file will be removed from the repository’s history.
Notes/Warnings:
- Permanent Deletion: This command permanently deletes the file from your working directory.
- Stages Deletion: The deletion itself is staged. You still need to commit to finalize the removal from your repository’s history. If you do not commit, and you accidentally run
git restore temp_file.txt
, it would bring the file back!
Summary:
Scenario / Goal | Command | Description | Notes / Warnings |
---|---|---|---|
Unstage changes in a single file | git restore --staged <file> | Moves specific file changes from staging to working dir. | Working directory changes are preserved. |
Unstage ALL changes in staging area | git restore --staged . | Moves all staged changes back to working directory. | Working directory changes are preserved. New untracked files remain untracked. |
Remove file from staging (keep locally) | git rm --cached <file> | Removes file from staging, but keeps it on your disk. | Ideal before adding to .gitignore . File becomes untracked locally. |
Remove file from staging AND delete locally | git rm -f <file> | Deletes file from disk and stages the deletion. | DANGER! File is permanently deleted from your working directory. Committing finalizes removal from repo. |
References (Official Git Documentation):
git restore
: https://git-scm.com/docs/git-restoregit reset
: https://git-scm.com/docs/git-resetgit rm
: https://git-scm.com/docs/git-rmgit status
: https://git-scm.com/docs/git-status
Author

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins.
In my free time, I write blogs on ckdbtech.com