Git Notes
Master git restore command to discard changes in working directory, unstage files, and restore files from specific commits with modern Git syntax.
If you have been using Git for a while, you probably know the confusing old syntax where git checkout did about fifteen different things depending on the arguments you passed. Starting with Git 2.23, the Git team introduced git restore as a dedicated command for one specific job: restoring file content. It handles discarding changes and unstaging files without the ambiguity that plagued git checkout.
Think of git restore as the "undo" button for your working directory and staging area. It answers two common questions every developer asks daily: "How do I throw away changes I do not want?" and "How do I unstage something I accidentally added?"
Discarding Changes in the Working Directory
When you have modified files but want to throw those changes away and return to the last committed version:
# Discard changes in a single file
git restore README.md
# Discard changes in multiple specific files
git restore src/app.js src/index.html
# Discard ALL changes in the entire working directory
git restore .
# Discard changes in a specific directory
git restore src/components/This is the equivalent of the old git checkout -- filename syntax, but far more readable and intentional. When you run git restore README.md, Git replaces the working directory version with the version from the staging area (or HEAD if nothing is staged).
Warning: Discarding working directory changes is irreversible. Unlike committed work which can be recovered through reflog, uncommitted changes that you discard with git restore are gone permanently. Always double-check with git diff before restoring.
# ALWAYS review before discarding
git diff README.md # See what you would lose
git restore README.md # Now discard with confidenceUnstaging Files
The second major use case is removing files from the staging area without losing your changes. You accidentally ran git add . and staged everything, but you only wanted to commit some files:
# Unstage a single file (changes remain in working directory)
git restore --staged config/secrets.env
# Unstage multiple files
git restore --staged src/debug.js src/temp-notes.txt
# Unstage everything
git restore --staged .This replaces the old git reset HEAD filename syntax. The key point is that --staged only affects the staging area. Your actual file modifications remain untouched in the working directory:
# Full workflow example
git add . # Oops, staged everything
git status # See everything is staged
git restore --staged secrets.env # Unstage the secrets file
git restore --staged *.log # Unstage all log files
git commit -m "feat: add new feature" # Commit only what should be committedRestoring from a Specific Commit
You can restore a file to the state it was in at any point in history using the --source flag:
# Restore a file from a specific commit
git restore --source=abc1234 src/config.js
# Restore from a branch
git restore --source=main src/config.js
# Restore from two commits ago
git restore --source=HEAD~2 src/config.js
# Restore a deleted file from the last commit that had it
git log --diff-filter=D --name-only # Find when it was deleted
git restore --source=HEAD~1 path/to/deleted-file.jsThis is incredibly useful when you want to see what a file looked like at a previous point without checking out the entire commit. The restored content goes into your working directory where you can inspect it, use it, or commit it.
Combining --staged and --source
You can combine flags for more precise control:
# Restore a file to both staging area AND working directory from a specific commit
git restore --source=HEAD~3 --staged --worktree src/module.js
# This puts the file in exactly the state it was 3 commits ago,
# both in staging and working directory, ready to commitThe --worktree flag (which is the default when no --staged is specified) explicitly targets the working directory. Using both together ensures complete restoration.
The Old Way Versus the New Way
Here is a complete comparison showing why git restore is superior for readability:
# DISCARDING CHANGES
# Old (confusing - checkout does too many things):
git checkout -- src/app.js
# New (clear intent):
git restore src/app.js
# UNSTAGING FILES
# Old (reset is for moving HEAD, not unstaging!):
git reset HEAD src/app.js
# New (obvious what it does):
git restore --staged src/app.js
# RESTORING FROM SPECIFIC COMMIT
# Old (is this switching branches or restoring?):
git checkout abc1234 -- src/app.js
# New (explicitly a restore operation):
git restore --source=abc1234 src/app.jsPractical Scenarios
Scenario 1: Accidental edit to a config file
# You accidentally modified database config while debugging
git diff src/config/database.yml # Review the accidental change
git restore src/config/database.yml # Discard it, back to committed stateScenario 2: Selective staging correction
# You want to commit feature code but accidentally staged test data
git add .
git restore --staged tests/fixtures/mock-data.json
git restore --staged .env.local
git commit -m "feat: implement search functionality"Scenario 3: Recovering a file you deleted
# You deleted a file but it is still in the last commit
rm src/utils/helpers.js # Accidentally deleted
git restore src/utils/helpers.js # Restored from HEADScenario 4: Comparing a file across versions
# Temporarily restore an old version to compare
cp src/api.js src/api.js.current # Backup current
git restore --source=HEAD~5 src/api.js # Get old version
diff src/api.js src/api.js.current # Compare them
git restore src/api.js # Put current back
rm src/api.js.current # Clean upCommon Mistakes
Mistake 1: Using git restore . without checking git diff first. You might throw away hours of work that you simply forgot to commit.
Mistake 2: Confusing --staged with working directory restore. Running git restore --staged file does NOT discard your changes. It only unstages them. The modifications remain in your working directory.
Mistake 3: Expecting git restore to work on untracked files. It only operates on tracked files. New files that were never committed cannot be "restored" because Git has no previous version of them.
Interview Questions
Q1: What is the difference between git restore and git checkout?
git restore (Git 2.23+) is a focused command that exclusively handles file restoration and unstaging. git checkout is an older overloaded command that handles branch switching, file restoration, and detached HEAD states all in one. The newer commands (git restore for files, git switch for branches) provide clearer intent and reduce confusion.
Q2: How do you discard all uncommitted changes safely?
First run git diff and git diff --staged to review what you are about to lose. Then use git restore . for working directory changes and git restore --staged . for staged changes. For a complete reset including untracked files, combine with git clean -fd. Always verify with git status afterward.
Q3: How do you unstage files without losing the changes?
Use git restore --staged filename which removes the file from the staging area but leaves your modifications intact in the working directory. This is the modern equivalent of git reset HEAD filename. You can then selectively re-add only what you want to commit.
Q4: Can git restore recover permanently deleted files?
If the file existed in a previous commit, yes. Use git restore --source=<commit> path/to/file to bring it back from any commit in history. If the file was never committed (only existed as an untracked file), Git cannot restore it because it was never tracked.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Git Restore - Discard Changes.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Git & GitHub topic.
Search Terms
git-github, git & github, git, github, undoing, changes, restore, git restore - discard changes
Related Git & GitHub Topics