Ad – 728×90
🚀 Getting Started

Undoing Changes in Git – restore, reset, revert

One of Git's most powerful promises is that you can always go back. But "going back" means different things depending on the situation — did you edit a file and want to discard it? Did you stage a file by accident? Did you commit something you shouldn't have? Each scenario has the right tool: git restore, git reset, or git revert. This lesson explains all three — and critically, when each one is safe vs destructive.

⏱️ 20 min read 🎯 Beginner 📅 Updated 2026

Three Scenarios for Undoing Changes

Before reaching for an undo command, identify which scenario you're in:

ScenarioWhere is the change?Right command
Discard edits to a file (not staged) Working directory only git restore <file>
Unstage a file (keep the edits) Staging area git restore --staged <file>
Undo a commit (local, not pushed) Repository history git reset HEAD~1
Undo a commit (already pushed / shared) Repository history git revert <commit>

git restore – Discard Working Directory Changes

git restore overwrites your working directory file with the version from the last commit (or from the staging area). It is the modern replacement for the old git checkout -- <file> command.

Discard changes to a specific file

Bash
# Discard all uncommitted changes to README.md
git restore README.md

# Discard changes to a file in a subdirectory
git restore src/utils.py
⚠️
git restore is DESTRUCTIVE — there is no undo

When you run git restore <file>, your uncommitted changes to that file are permanently lost. Git has no way to recover them because they were never committed. Double-check with git diff before running this command if you're not sure what you're discarding.

Discard ALL unstaged changes in the working directory

Bash
# Restore ALL modified tracked files to their last committed state
git restore .

# This does NOT delete untracked files (new files you haven't added yet)
# To also remove untracked files, use: git clean -fd

Unstaging Files with git restore --staged

If you staged a file with git add but changed your mind, use --staged to move it back to the working directory without discarding your changes.

Bash
# Unstage a specific file (keeps your edits in the working directory)
git restore --staged config.py

# Unstage all staged files
git restore --staged .

This is the safe version of undoing a git add — your changes are preserved; they just move from "staged" back to "modified but not staged".

Ad – 336×280

git reset – Undo a Commit

git reset moves the current branch pointer backward in history, effectively "uncommitting" one or more commits. It comes in three modes, from safest to most destructive:

--soft: undo the commit, keep changes staged

Bash
# Undo the last commit — changes go back to the staging area
git reset HEAD~1 --soft

# HEAD~1 means "one commit before HEAD"
# HEAD~2 would undo the last two commits

Use --soft when you want to re-commit with a different message or combine it with other staged changes.

--mixed (default): undo the commit, unstage changes

Bash
# Undo the last commit — changes go back to the working directory (not staged)
git reset HEAD~1
# Same as:
git reset HEAD~1 --mixed

Use --mixed (the default) when you want to rework your changes before committing again. Your files are untouched; only the staging area and commit history are rolled back.

--hard: undo the commit AND discard all changes

Bash
# DANGER: Undo the last commit AND permanently discard all its changes
git reset HEAD~1 --hard
⚠️
Never use git reset --hard on shared or pushed commits

--hard discards commits and changes permanently from your local repository. If you've already pushed those commits to a remote branch that others are using, running git reset --hard followed by a force push will rewrite shared history — causing severe conflicts for your teammates. Reserve --hard for private, local-only branches. For shared branches, use git revert instead.

git revert – The Safe Way to Undo a Pushed Commit

git revert does not remove commits from history. Instead, it creates a brand-new commit that applies the exact opposite of the changes in the specified commit. The original commit remains in history — it's simply counteracted. This is the safe method for undoing changes on shared branches.

Bash
# Revert the most recent commit
git revert HEAD

# Revert a specific commit by hash
git revert a3f8c2d

# Revert without automatically opening the commit message editor
git revert a3f8c2d --no-edit
Output
[main f9e8d7c] Revert "Add input validation to calculate function"
 1 file changed, 3 deletions(-)

A new commit appears on top of history with the message "Revert '...'". The original commit is still there — the history is preserved, and your teammates' work is unaffected.

Use git revert on main/shared branches

Any time you need to undo something on main, develop, or any branch that other people have pulled from, use git revert. It's the professional, non-destructive approach to fixing mistakes in shared history.

Comparison: restore vs reset vs revert

CommandWhat it undoesDestructive?Safe on shared branch?Reversible?
git restore <file> Unstaged working dir changes Yes — changes lost N/A (local only) No
git restore --staged <file> Staged changes (unstages them) No — changes kept N/A (local only) Yes (re-add)
git reset --soft Last commit (keeps staged) No No — rewrites history Yes (recommit)
git reset --mixed Last commit (unstages changes) No No — rewrites history Yes (re-add & commit)
git reset --hard Last commit + all its changes Yes — changes lost No — rewrites history Only via reflog
git revert A commit (via new counter-commit) No Yes — adds to history Yes (revert the revert)
ℹ️
Last resort: git reflog

Even after git reset --hard, Git keeps a local reference log (git reflog) for about 90 days. If you accidentally nuked something important, run git reflog to find the commit hash, then use git reset --hard <hash> to restore it. This only works on your local machine before Git's garbage collector runs.

📋 Summary

  • git restore <file> — discard unstaged working directory changes (destructive, no recovery).
  • git restore . — discard ALL unstaged changes in the whole project.
  • git restore --staged <file> — unstage a file without discarding changes (safe).
  • git reset HEAD~1 --soft — undo the last commit, keep changes staged.
  • git reset HEAD~1 --mixed (default) — undo the last commit, move changes back to working directory.
  • git reset HEAD~1 --hard — undo the last commit AND discard all its changes (destructive).
  • git revert <commit> — creates a new commit that reverses a past commit; safe for shared/pushed branches.
  • If you accidentally used --hard, check git reflog within 90 days to attempt recovery.

FAQ

What is the difference between git reset and git revert? +

git reset moves the branch pointer backward, effectively removing commits from the current branch's history. It rewrites history — which is why it's unsafe on shared branches. git revert adds a new commit that undoes the changes from a past commit without touching the existing history. The original commit remains. For anything that has been pushed or shared with others, always prefer git revert.

Can I undo multiple commits at once with git reset? +

Yes — HEAD~N moves back N commits. For example, git reset HEAD~3 --soft undoes the last 3 commits and puts all their changes back into the staging area. You can then re-commit them as one combined commit. You can also reset to a specific commit hash: git reset a3f8c2d --mixed.

I ran git restore and lost my changes. Can I get them back? +

Unfortunately, git restore on unstaged changes has no recovery mechanism in Git itself — those changes were never committed, so Git has no snapshot of them. Your best hope is your editor's local undo history (Ctrl+Z) if you haven't closed the file. Some editors like VS Code also keep a local file history (Timeline view). For future protection, consider committing work-in-progress as a "WIP" commit before experimenting, then amend or squash it later.

Is there a way to undo changes to a specific part of a file? +

Yes — use git restore -p <file> (patch mode, same as git add -p but in reverse). Git walks through each changed hunk and asks if you want to discard it. This gives you fine-grained control, letting you keep some changes while discarding others within the same file.