To throw away edits to tracked files and go back to the last commit, run git restore <file> for one file or git restore . for all of them. On Git before 2.23, use git checkout -- <file> instead. To delete files Git is not yet tracking, you need git clean -fd. None of this is recoverable once it runs, so be sure before you press enter.
That is the whole answer. The rest of this page explains which command matches which situation, because "discard local changes" turns out to mean three slightly different things depending on whether a file is tracked, staged, or brand new.
What "local changes" actually means
When you edit files in a repository, Git sorts them into states. Knowing the state tells you which command to reach for. If the difference between these is fuzzy, the staging area walkthrough is worth ten minutes first.
| State | What it means | How to discard it |
|---|---|---|
| Modified, tracked, unstaged | You edited a file Git already knows about, no git add yet | git restore <file> |
| Modified, tracked, staged | Same, but you ran git add on it | git restore --staged <file> then git restore <file> |
| Untracked | A new file Git has never seen (no git add ever) | git clean -f |
| Everything | Throw away the whole working tree | git reset --hard plus git clean -fd |
Run git status first, every time. It tells you exactly which bucket each file is in, and it spells out the discard command for that bucket right in its output. Reading status before discarding is the single habit that prevents most "I lost my work" moments.
Discard changes to a tracked file
This is the common case: you changed a file, the change is wrong, and you want the file back the way it was at the last commit.
# discard changes to one file
git restore path/to/file.js
# discard changes to everything in the working tree
git restore .
git restore arrived in Git 2.23 (August 2019) to split the overloaded git checkout into two clearer commands: git restore for files, git switch for branches. It is the modern, recommended way to do this.
On an older Git, the equivalent is:
# pre-2.23 syntax, still works on every version
git checkout -- path/to/file.js
git checkout -- .The -- matters. It tells Git "everything after this is a file path, not a branch or flag," which avoids ambiguity if a file happens to share a name with a branch. Both forms do the same thing: overwrite your working copy with the version from HEAD, the last commit on your current branch.
Discard a change you already staged
If you ran git add on the file, it is staged, and a plain git restore will not touch it. Unstage it first, then discard:
# step 1: move it out of the staging area (the file keeps your edits)
git restore --staged path/to/file.js
# step 2: now discard the edits in the working tree
git restore path/to/file.jsThe two-step is deliberate. git restore --staged only resets the staged copy back to HEAD; your edits are still sitting in the working file. The second git restore is what actually throws those edits away. If you only want to unstage and keep editing, stop after step one. A common reason to be here at all is that a pull or merge refused to run and complained that your local changes would be overwritten by merge; discarding the staged and working edits is one way to clear that block. For undoing a commit rather than staged edits, see undoing the last commit and the reset vs revert comparison.
Delete untracked files with git clean
Here is the trap that catches beginners: git restore and git checkout only operate on files Git is already tracking. A brand-new file you have never committed is untracked, and Git will leave it completely alone. To remove untracked files you need git clean.
Always do a dry run first. -n shows what would be deleted without deleting anything:
# DRY RUN: list what clean would remove, delete nothing
git clean -nOnce you are happy with that list, run it for real:
# delete untracked files
git clean -f
# delete untracked files AND untracked directories
git clean -fd
# also remove files your .gitignore is ignoring (build output, etc.)
git clean -fdxThe flags:
-fis "force." Git refuses to delete files without it, on purpose, because this is destructive.-dextends the delete to untracked directories, not just loose files.-xalso removes files matched by your .gitignore rules, likenode_modulesor abuild/folder. Use this one carefully; it wipes things you usually want to keep, like local env files.
git clean -fdx is the nuclear option for a truly pristine checkout. I reach for it when a build is poisoned by stale artifacts and I want the directory to look exactly like a fresh git clone.
Throw everything away and reset to the last commit
To return the entire working tree to the last commit, both tracked edits and untracked junk, you need two commands. reset --hard handles tracked files; clean -fd handles the untracked ones.
# discard all changes to tracked files
git reset --hard
# then remove every untracked file and directory
git clean -fdgit reset --hard rewinds tracked files to HEAD and blows away both staged and unstaged edits in one move. It does not touch untracked files, which is why the clean is still needed for a complete wipe. If you want to reset to a specific commit rather than the current one, name it: git reset --hard <commit-hash>.
A safer middle ground, if you might want the work back later, is to stash instead of discard:
# tuck everything away instead of deleting it
git stash --include-untrackedThat puts your changes on a stack you can restore with git stash pop. When you are not fully sure you want the work gone, stash it; the git stash guide covers the workflow. Stashing costs nothing and buys you an undo.
This is irreversible. Really.
The commands on this page do not move files to a trash can. They overwrite or delete them at the filesystem level. Git's safety net, git reflog, only tracks committed history. Edits you never committed leave no trace once git restore, git reset --hard, or git clean runs.
In plain terms:
- Committed work can almost always be recovered, even after a bad
reset --hard, using the reflog. The commit is still in the object database. - Uncommitted work (anything you discard here) is gone. No reflog entry, no dangling commit, nothing to recover.
So the discipline is simple: run git status to see what you are about to lose, run git clean -n before any real git clean, and when in doubt, git stash instead of discard. Committing early and often also helps, because a commit is a recoverable checkpoint. If your commit cadence needs work, the Git for Beginners hub and the commit message conventions are good next reads.
FAQ
Sources
Authoritative references this article was fact-checked against.
- git-restore: official Git documentationgit-scm.com
- git-clean: official Git documentationgit-scm.com
- Pro Git: Git Basics, Undoing Thingsgit-scm.com





