Git gives you several ways to undo work, but they do different things. You might have committed too early, forgotten a file, introduced a bug, or pushed a change that teammates already have. Before choosing a command, decide whether you want to move a branch, create a new commit that reverses another, or restore a file.
git resetmoves the current branch to another commit and can keep, unstage, or discard the changes.git revertcreates a new commit that reverses an earlier commit without rewriting shared history.git restoreupdates selected paths in the index or working tree; it does not remove a commit from branch history.
Inspect your work first
Check which branch you are on, whether you have uncommitted changes, and which commit you intend to undo:
git status
git log --oneline --decorate -5
In a history such as A -> B -> C -> D (HEAD), HEAD points to the current commit D and HEAD~1 refers to its first parent C. Save or commit unrelated work before running commands that change the index or working tree.
Undo the latest local commit and keep changes staged
Use a soft reset when you want to remove the latest commit from the current branch but keep its changes staged:
git reset --soft HEAD~1
git status
This is useful when you forgot a file, want to revise the commit message, or plan to combine the changes into a new commit. The branch moves back one commit; the changes from the removed commit remain in the index, ready to commit again.
Keep changes but unstage them
A mixed reset moves the branch back and leaves the changes in your working tree, but unstages them. Mixed is the default mode, so these commands have the same effect:
git reset --mixed HEAD~1
# or
git reset HEAD~1
You can then review the files and stage only the parts you want with git add.
Discard the latest commit's tracked changes
A hard reset moves the branch, index, and tracked working-tree files to the target commit:
git status
git reset --hard HEAD~1
Destructive: git reset --hard can discard staged changes and uncommitted edits to tracked files. Confirm the branch and status first, and back up work you may need. Untracked files are not removed by reset, but they are not protected by a commit either.
To move back more than one commit, replace HEAD~1 with the appropriate parent, such as HEAD~3. Soft and mixed resets preserve the changes from the commits you move past; a hard reset does not preserve those tracked changes in the working tree.
Undo a commit that has already been shared
If a commit has been pushed or other people may have based work on it, prefer git revert. Revert records a new commit that applies the inverse of the selected commit, preserving the existing history:
git revert <commit-hash>
For the latest commit, git revert HEAD is a common choice. Resolve any conflicts Git reports, review the result, and complete the revert. Reverting a merge commit requires choosing a mainline parent; check the command's help and your branch history before doing that.
Restore or unstage an individual file
Use git restore when you want to change a path without moving the branch:
# Unstage a file while keeping its working-tree edits
git restore --staged -- path/to/file
# Discard unstaged edits to a file, restoring it from the index
git restore --worktree -- path/to/file
# Restore a file from a commit into both the index and working tree
git restore --source=<commit-hash> --staged --worktree -- path/to/file
The second command discards that file's unstaged edits, so inspect or back them up first. The -- separates options from the path and is helpful when a filename could be mistaken for an option.
Recover a commit after a reset
If a commit seems to have disappeared after a reset, inspect the reflog, which records recent local movements of references such as HEAD:
git reflog
Find the commit hash from before the reset, then preserve it on a new branch before changing your current branch again:
git branch recovery-before-reset <commit-hash>
git show --stat recovery-before-reset
Review the recovered commit and its files before deciding what to do next. Reflog entries are local and can expire; they are not a substitute for a backup. A reflog can help recover commits, but it does not generally restore uncommitted edits that were never recorded in Git.
Common situations
Fix the latest commit message or add a forgotten file
For a local commit that has not been shared, a soft reset keeps its changes staged so you can create a corrected commit. For a message-only correction, git commit --amend is often more direct. Avoid amending a commit that teammates already use unless your team has agreed to rewrite that shared history.
Remove a bad commit from a shared branch
Use git revert <commit-hash> to create a compensating commit. Avoid resetting a shared branch and force-pushing over teammates' history; coordinate with the team if history has to be rewritten.
Undo only one file
Use git restore with the appropriate source and target. This keeps unrelated files and commits untouched.
Quick reference
- Undo a local commit and keep changes staged:
git reset --soft HEAD~1. - Undo a local commit and keep changes unstaged:
git reset HEAD~1. - Discard a local commit's tracked changes:
git reset --hard HEAD~1(verify and back up first). - Reverse a shared commit:
git revert <commit-hash>. - Unstage or restore a file:
git restorewith--staged,--worktree, or both. - Find a commit after a reset:
git reflog, then preserve it on a recovery branch.
Rule of thumb: reset local, unpublished history when you want to move the branch; revert shared commits when you want to preserve history; restore paths when you only need to change files. Check git status before destructive commands.