← Back to Articles         
Git Undo Changes, Reset, Restore, and Revert

Git Undo Changes, Reset, Restore, and Revert

Published on 03 Oct 2026     7 min read Git & GitHub
Undoing Changes

Git Undo Changes, Reset, Restore, and Revert

1. How do you discard local changes and unstage a file using git restore?

What is git restore?

git restore is used to restore files in your working directory or remove files from the staging area.

Two common uses are:

  • Discard modifications made to a file.
  • Unstage a file that was added using git add.

A. Discard Local Changes

Suppose you modified:

Login.cs

but have not staged it yet.

Check:

git status

You might see:

modified: Login.cs

To discard the changes:

git restore Login.cs

The file is restored to its version from the index (normally matching the last commit if you haven't staged anything).

To discard changes in all tracked files:

git restore .

Important

This can permanently discard uncommitted working-directory changes.

Modified Login.cs
      ↓
git restore Login.cs
      ↓
Changes discarded

B. Unstage a File

Suppose:

git add Login.cs

Now Login.cs is in the staging area.

To remove it from staging:

git restore --staged Login.cs

The changes remain in your working directory.

Working Directory
       ↓
    git add
       ↓
Staging Area
       ↓
git restore --staged
       ↓
Working Directory

So:

git restore Login.cs

and:

git restore --staged Login.cs

perform very different operations.

Simple Comparison

Command Purpose
git restore file Discard working-directory changes
git restore --staged file Unstage file but keep changes
git restore . Discard changes in all tracked files

Key Points

  • git restore works mainly with file-level changes.
  • git restore --staged removes a file from staging.
  • Unstaging does not delete your modifications.
  • git restore <file> can discard uncommitted modifications, so use it carefully.
  • It does not remove untracked files.

2. What is the difference between git reset and git revert?

Both commands can be used to undo changes, but they work very differently.

git reset

git reset moves the current branch/HEAD to another commit and can also modify the staging area and working directory depending on the mode.

Suppose:

A --- B --- C
          HEAD

Execute:

git reset --hard B

Now:

A --- B
      HEAD

From the branch's visible history, commit C has been removed.

Therefore, reset is commonly used for local/unpublished history.


git revert

git revert does not remove the old commit.

Instead, it creates a new commit that reverses the changes introduced by an earlier commit.

Before:

A --- B --- C

Execute:

git revert C

After:

A --- B --- C --- D

Here:

C = original commit
D = commit reversing C

The history is preserved.

That makes revert generally safer for commits already shared with other developers.


reset vs revert

git reset git revert
Moves branch/HEAD backward Creates a new undo commit
Can rewrite branch history Preserves existing history
Useful for local/unpublished commits Useful for shared/pushed commits
Can discard changes with --hard Does not delete the original commit
May require force push if history was already pushed Normally allows a regular push

Key Points

A useful rule is:

Not pushed
    ↓
reset can be appropriate

Already pushed/shared
    ↓
revert is usually safer

3. What is the difference between git reset --soft, --mixed, and --hard?

The main difference is what Git does with:

  1. Commit history / HEAD
  2. Staging area
  3. Working directory

Suppose:

A --- B --- C
          HEAD

You want to reset from C back to B.


git reset --soft

git reset --soft HEAD~1

This moves HEAD back one commit but keeps the changes staged.

Commit C removed from branch history
           ↓
Changes remain staged

You can immediately recommit:

git commit -m "New commit message"

When useful

For example, you committed too early or want to recreate the last commit differently.


git reset --mixed

git reset --mixed HEAD~1

Or simply:

git reset HEAD~1

--mixed is the default.

It:

  • Moves HEAD back.
  • Removes the changes from staging.
  • Keeps the changes in your working directory.
Commit C removed
      ↓
Changes unstaged
      ↓
Changes still available locally

You can modify the files again and selectively stage them.


git reset --hard

git reset --hard HEAD~1

It:

  • Moves HEAD back.
  • Resets the staging area.
  • Resets tracked files in the working directory.
Commit C removed
      ↓
Staging changes removed
      ↓
Working-directory changes removed

Use this carefully because it can discard work.


Simple Comparison

Reset Type Commit Staging Area Working Files
--soft Reset Changes kept staged Changes kept
--mixed Reset Changes unstaged Changes kept
--hard Reset Reset Tracked changes discarded

An easy way to remember:

--soft
Keep everything staged

--mixed
Keep changes, but unstage them

--hard
Discard tracked changes too

Key Points

  • --soft → safest when you want to recommit immediately.
  • --mixed → keeps your code but unstages it.
  • --hard → can discard local work.
  • --mixed is the default for git reset.
  • HEAD~1 means one commit before the current commit.

4. How do you undo the last commit before it has been pushed?

If the commit has not been pushed, git reset is commonly used.

Suppose:

A --- B --- C
          HEAD

You accidentally committed C.

Option 1: Undo Commit but Keep Changes Staged

git reset --soft HEAD~1

Result:

A --- B
      HEAD

Changes from C → staged

This is useful when you want to correct something and recommit.

For example:

git reset --soft HEAD~1
git commit -m "Correct commit message"

If you only need to change the latest commit message, an even simpler command is:

git commit --amend -m "Correct commit message"

Option 2: Undo Commit and Unstage Changes

git reset HEAD~1

Equivalent to:

git reset --mixed HEAD~1

The commit is undone, but your file changes remain.


Option 3: Undo Commit and Discard Changes

git reset --hard HEAD~1

This removes the commit and discards its tracked file changes from the working tree.

Use this only when you are sure you do not need the changes.

Key Points

For an unpushed last commit:

Keep staged
    ↓
git reset --soft HEAD~1

Keep changes but unstage
    ↓
git reset --mixed HEAD~1

Discard changes
    ↓
git reset --hard HEAD~1

5. How do you safely undo a commit that has already been pushed to a shared branch?

For a commit already pushed to a shared branch, the normal safe approach is:

git revert <commit-id>

Why?

Because other developers may already have the original commit.

Suppose the remote history is:

A --- B --- C

Other developers may already have pulled C.

If you reset:

git reset --hard B

and force-push, you rewrite the shared branch history.

That can cause synchronization problems for other developers.

Instead, use:

git revert C

Git creates:

A --- B --- C --- D

where:

D = reverses the changes introduced by C

Then push normally:

git push

Simple Example

Check the commit history:

git log --oneline

Example:

8a25c10 Add payment feature
7b12d40 Add login feature
3c21a11 Initial commit

Suppose the payment commit must be undone:

git revert 8a25c10

Git creates a new revert commit.

Then:

git push

History becomes conceptually:

Initial
   ↓
Login
   ↓
Payment
   ↓
Revert Payment

The original payment commit remains in the history, but its changes are reversed.

Why Not reset --hard?

Avoid doing this casually on a shared branch:

git reset --hard HEAD~1
git push --force

because it rewrites published history and can interfere with other developers' work.

Key Points

  • For local/unpushed history, reset can be appropriate.
  • For pushed/shared history, prefer revert.
  • revert creates a new commit.
  • The original commit remains visible.
  • Revert is collaboration-friendly because it does not normally rewrite existing shared history.

Quick Interview Summary

Discard file changes
→ git restore file

Unstage file
→ git restore --staged file

Undo unpushed commit, keep staged
→ git reset --soft HEAD~1

Undo unpushed commit, keep unstaged
→ git reset --mixed HEAD~1

Undo unpushed commit and discard changes
→ git reset --hard HEAD~1

Undo pushed/shared commit safely
→ git revert <commit-id>
← Back to Articles