| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | git 2.52.0 |
| Applies to | Any host with Git installed |
| Privilege | Normal user |
| Scope | Discard current uncommitted edits in the working tree and staging area with git restore, git reset --hard, and git clean. Brief notes on stash and committed history. Scenario sections match git status output — not a full revert, reset, or history-restore deep dive. |
| Related guides | Git restore examples Git reset examples Git clean Git unstage files Git stash explained |
Discarding changes means throwing away local edits you no longer want. Git stores those edits in different places — modified files, the staging area, untracked paths, or commit history — and each place has its own command.
Start with git status -sb. The sections below are independent scenarios keyed to what that output shows. Pick the row that matches your status line — not a lab sequence to run top to bottom.
Choose the Right Discard Command
Git has no single discard subcommand. Match your status line to the smallest command that does what you need:
git status -sb |
What you want | Command |
|---|---|---|
M file |
Discard unstaged change | git restore file |
M file |
Unstage, keep content on disk | git restore --staged file |
M file |
Discard the staged change and restore the file to HEAD | git restore --staged --worktree file |
MM file |
Discard both staged and unstaged content in this file | git restore --staged --worktree file |
?? file |
Remove untracked files | preview git clean -n, then git clean -f |
?? dir/ |
Remove untracked directories too | preview git clean -nd, then git clean -fd |
| Many tracked changes | Reset all tracked files to HEAD |
git reset --hard HEAD |
| Unsure about deleting | Save first | git stash push |
Committed history is a different problem. This article focuses on uncommitted work; see Git revert examples or Git reset examples when the change is already a commit.
Check What Git Sees First
When to use this: you want to discard something but are not sure whether it is staged, unstaged, or untracked.
Short status with branch and change columns:
git status -sb## main
M README.md
M app.txt
MM config.yml
?? scratch.txtRead the two change columns from left to right:
- First column — staging area:
Mmeans staged; space means not staged. - Second column — working tree:
Mmeans modified on disk. ??— untracked;git restoreandgit reset --harddo not remove these paths.
MM means you staged one version, then edited the file again afterward, so Git now has one changed version in the index and another changed version in the working tree. For one file, git restore --staged --worktree file resets both from HEAD in a single command — you do not need git reset --hard HEAD unless many tracked files must go.
Discard Unstaged Changes
Scenario: you edited a tracked file and have not run git add, or you already unstaged it. Status shows a space before M:
## main
M app.txtPlain git restore updates the working tree from the index, not directly from HEAD:
git restore app.txtWhen nothing is staged for that file, the index normally matches HEAD, so the unstaged edit disappears. If the file is also staged (M in the first column), plain git restore only realigns the working tree to the staged snapshot — use git restore --staged --worktree file when you want both gone.
After a successful restore, status should be clean for that path:
git status -sb## mainFor every tracked file with an unstaged edit:
git restore .Staged entries and untracked ?? paths are left unchanged.
Unstage Without Deleting Changes
Scenario: you ran git add and want the file out of the index while keeping your edits on disk. Status shows M in the first column and a space in the second:
## main
M app.txtMove the file out of the staging area only:
git restore --staged app.txtThe index no longer lists the change; disk content is unchanged:
git status -sb## main
M app.txtTo unstage every staged file at once:
git restore --staged .When you also want to discard the staged change and restore the file to HEAD — not just move it back to the working tree — use git restore --staged --worktree file on that path instead.
Discard Staged and Unstaged Changes
Scenario: status shows MM on one file, or you need the entire repository back to the last commit.
One file (MM)
MM means Git holds one version in the index and a different version on disk. To discard both for a single path:
## main
MM config.ymlRestore index and working tree from HEAD in one step:
git restore --staged --worktree config.ymlBecause --staged is set and no --source is given, Git defaults the source to HEAD. Both copies match the last commit:
git status -sb## mainPrefer this over git reset --hard HEAD when only one file should change — --hard affects every tracked file in the repository.
Whole repository
When many tracked files are dirty and you intentionally want all of them to match HEAD:
git reset --hard HEADHEAD is now at aca4fec add configConfirm every tracked file matches HEAD:
git status -sb## maingit reset --hard HEAD does not remove untracked ?? paths — run git clean when those should go too.
Remove Untracked Files and Directories
Scenario: status lists ?? paths. Those files were never committed — restore and reset ignore them.
## main
?? build/
?? scratch.txtPreview what git clean would delete:
git clean -nWould remove scratch.txtFor directories, preview with -d:
git clean -ndDelete untracked files and directories after you are satisfied with the preview:
git clean -fdRemoving build/
Removing scratch.txtAlways run -n or -nd before -f or -fd on an unfamiliar repository. git clean -fd does not remove ignored files; -x includes them, so use -x only when that is intentional.
Save Changes With Stash Instead
Scenario: you need a clean tree but are not sure the edits can be permanently deleted.
git stash push saves tracked staged and unstaged changes. Add -u if you also need untracked files saved — by default, stash does not include ?? paths:
git stash push -m "WIP before discard"Use this before git reset --hard or git clean when you might want the work back. Untracked files left after stash still need git clean or git stash push -u if you want them preserved. See Git stash explained for apply, pop, and drop.
When Changes Are Already Committed
Scenario: git status is clean but the last commit (or an older one) should be undone.
This article stops at uncommitted edits. For shared branches, prefer git revert — it adds a new commit that undoes a prior one without rewriting history. Local-only cleanup may use git reset --soft, --mixed, or --hard against HEAD~1; see Git revert examples and Git reset examples for those workflows.
Never run git reset --hard on commits you already pushed unless your team expects a force push.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
git restore file ran but content still looks wrong |
File is staged (M or MM in first column) |
git restore --staged --worktree file for that path |
Only part of an MM file was cleared |
Plain git restore realigns working tree to index, not HEAD |
git restore --staged --worktree file |
git reset --hard ran but ?? files remain |
Untracked paths are outside reset scope | git clean -fd after preview with git clean -n |
Used --hard and lost edits on unrelated files |
--hard resets every tracked file |
Prefer git restore --staged --worktree file for single-file discard |
| Not sure you want permanent loss | Destructive command on the wrong state | git stash push first, then discard from a clean tree |
References
Git documentation: git-restore
Git documentation: git-reset
Git documentation: git-clean
Git documentation: git-stash
Git documentation: git-status
Summary
Discarding changes in Git starts with git status -sb. The two change columns tell you whether edits live in the working tree, the staging area, or both — and ?? marks paths that only git clean removes.
Plain git restore file replaces the working-tree copy from the index; when nothing is staged, that matches HEAD. Use git restore --staged to unstage without deleting disk content, and git restore --staged --worktree file when one MM or fully staged file should match HEAD without touching anything else. Reserve git reset --hard HEAD for when every tracked file must go.
Preview untracked deletions with git clean -n before git clean -fd; ignored files need -x and are left alone by default. When you might need tracked work again, git stash push saves staged and unstaged edits — add -u when untracked paths should be included. Committed history belongs to git revert or git reset — pick the smallest command that matches your status line rather than reaching for --hard first.

