Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›Git & GitHub›Undoing Changes — reset, revert, restore

Git Fundamentals

Undoing Changes — reset, revert, restore

This guide covers the essential Git tools for correcting mistakes at different stages of the development lifecycle. Understanding these commands is critical for maintaining a clean, professional project history without losing work. You should reach for these tools whenever you need to backtrack, fix a logic error, or clean up your current working environment.

Restoring the Working Directory

The 'git restore' command is your primary tool for discarding uncommitted changes in your working directory. When you modify a file, Git tracks those changes, but they are not yet part of your repository's history. Sometimes, you may realize that your experiment failed or that you accidentally introduced a syntax error that you wish to abandon entirely. By running 'git restore', you instruct Git to copy the version of the file from the last commit (the HEAD) over your current, modified version. This is a destructive operation because it deletes your local changes, returning the file to a known good state. Understanding this process is vital because it separates your experimental workspace from the repository's permanent record, allowing you to iterate freely while keeping the ability to instantly revert to a safe starting point at any moment.

# Discard local changes in a specific file
git restore app/database.js

# Discard all changes in the entire current directory
git restore .

Unstaging Changes

Before you create a commit, you move files into the staging area using 'git add'. This serves as a buffer that allows you to curate exactly what goes into the next snapshot of your project. However, it is very common to accidentally add a file that you did not intend to include, or perhaps you realized you are not quite ready to commit that specific file yet. The 'git restore --staged' command allows you to remove files from this index without actually deleting or reverting the changes you made to the file content itself. This command is conceptually powerful because it manages the transition between your working directory and the git index. By mastering this, you maintain precise control over your commit granularity, ensuring that your project's history remains logical, segmented, and free from accidental inclusions.

# Unstage a specific file, keeping local changes intact
git restore --staged config/settings.json

# Unstage everything currently staged
git restore --staged .

Resetting the Commit History

When you need to undo a commit entirely, 'git reset' is the go-to command. Unlike reverting, which adds a new commit, resetting actually rewinds the project history. If you use the '--soft' flag, the changes from the undone commit remain in your staging area, allowing you to fix them or refine the commit message. If you use '--hard', you move the HEAD pointer back to a previous commit and force the working directory and staging area to match that exact state, effectively deleting all work that happened after that point. This is a very powerful but dangerous command because it rewrites project history. You should only use reset on local, unpushed branches, as altering history that has already been shared with collaborators can cause significant synchronization issues and confusion for the rest of your team.

# Move HEAD back one commit, keeping changes staged
git reset --soft HEAD~1

# Move HEAD back one commit, destroying all changes
git reset --hard HEAD~1

Reverting Published Commits

When you have already pushed your work to a shared repository, you must avoid 'git reset' to prevent breaking history for your team. Instead, you use 'git revert'. This command does not delete or rewrite past commits; instead, it creates a brand new 'inverse' commit that effectively cancels out the changes introduced by a previous one. By doing this, the history remains intact—everyone can see that a change was made and that it was subsequently undone. This approach follows the principle of additive history, which is considered a best practice in collaborative environments. The reason this is safer is that it never causes conflicts for other developers who might have pulled your previous commits. It provides a clean, audit-friendly way to roll back features or fix broken deployments while maintaining a transparent and immutable project timeline.

# Create a new commit that undoes the changes of the last commit
git revert HEAD

# Revert a specific commit by its unique hash
git revert a1b2c3d

Selecting the Right Tool

Choosing between reset, revert, and restore depends entirely on the state of your work and whether it has been shared with others. 'git restore' is for cleaning your current mess without touching the repository history. 'git reset' is for local cleanup where you want to reshape history, effectively pretending that specific commits never happened. Finally, 'git revert' is for undoing mistakes that have already been made public, ensuring that your team's synchronization is never compromised. By internalizing these distinctions, you move from being a user of Git to being a manager of your project's lifecycle. A deep understanding of these tools allows you to work confidently and proactively, knowing that no mistake is permanent as long as you understand the mechanics of how Git manages the relationship between your files, the index, and the commit graph.

# Summary flow: Fix locally, then stage, then decide how to revert
git restore src/main.js # Discard local mistake
git add src/main.js # Add final changes
git commit -m "Fix logical bug" # Finalize

Key points

  • Use git restore to discard changes in your working directory before they are staged.
  • Use git restore --staged to remove files from the index while keeping local edits.
  • The git reset command rewrites commit history by moving the branch pointer.
  • The --hard flag for reset is destructive and will delete any uncommitted work.
  • Use git revert to safely undo public commits without changing the existing history.
  • Revert creates a new commit that applies the inverse of the targeted change.
  • Never use git reset on branches that have already been pushed to a remote.
  • Understanding the HEAD pointer is essential to mastering all undo operations in Git.

Common mistakes

  • Mistake: Using 'git reset --hard' without checking if there are uncommitted local changes. Why it's wrong: It permanently deletes all tracked changes in your working directory. Fix: Use 'git stash' first to save changes or 'git checkout'/'git restore' if you only want to discard specific file changes.
  • Mistake: Confusing 'git revert' with 'git reset' when working on a shared repository. Why it's wrong: 'git reset' rewrites commit history, which causes significant problems for collaborators. Fix: Use 'git revert' to create a new inverse commit that keeps the project history intact for everyone.
  • Mistake: Assuming 'git restore' is identical to 'git checkout'. Why it's wrong: 'git checkout' is overloaded and handles both branching and file restoration, while 'git restore' was introduced to provide a clearer, more specialized command for file operations. Fix: Use 'git restore' for clarity when you only need to discard changes in the working directory.
  • Mistake: Running 'git reset --soft' expecting it to remove recent commits from the repository history. Why it's wrong: '--soft' only moves the HEAD pointer and leaves your changes in the staging area, not actually deleting the commit from the remote. Fix: Ensure you understand the distinction between soft, mixed, and hard resets before modifying local commit history.
  • Mistake: Forgetting that 'git revert' creates a new commit. Why it's wrong: Users often expect it to delete the commit entirely, leading to confusion when they see the 'revert' commit in their logs. Fix: Accept that 'revert' is an additive process and use it as the standard way to safely undo public changes.

Interview questions

How would you unstage a file that you accidentally added to the staging area before committing it?

To unstage a file while keeping your changes intact, you use the 'git restore --staged <file>' command. This effectively moves the file from the index back to your working directory. It is the safest way to correct a mistake if you accidentally staged a file that is not ready for a commit, as it does not destroy your work, it simply alters the state of the Git index.

What is the primary difference between using 'git restore' and 'git reset' when you want to discard local changes?

The 'git restore' command is designed to be a more intuitive and specific tool for discarding changes in the working directory or staging area, essentially undoing local edits. Conversely, 'git reset' is a more powerful and complex command that moves the HEAD pointer to a specific commit. While 'git restore' is focused on file-level operations, 'git reset' is often used for project-level state manipulation, such as undoing commits while keeping or destroying work.

Explain how 'git revert' works and why it is considered a safer alternative to 'git reset' when working on shared branches.

The 'git revert' command creates a brand new commit that performs the exact inverse action of a previous commit, effectively undoing it without erasing history. This is significantly safer than 'git reset --hard' on shared branches because it does not rewrite the commit history. By adding a new commit instead of deleting old ones, you prevent synchronization issues for teammates who have already pulled those commits into their local repositories.

If you have accidentally committed sensitive information to a local repository, how do you handle it using 'git reset'?

To fix a recent sensitive commit, you can use 'git reset --soft HEAD~1'. This command moves the HEAD pointer back to the previous commit while keeping your changes in the staging area. You can then unstage the sensitive file, delete it or scrub it, and then commit again. This allows you to rewrite your last commit locally before pushing, ensuring that the mistake never reaches the remote server or your colleagues.

Compare the impact of 'git reset --hard' versus 'git checkout' when switching between branches or discarding changes.

The command 'git reset --hard' is destructive; it forces the working directory and the index to match a specific commit, causing all uncommitted local changes to be permanently lost. On the other hand, 'git checkout' is primarily used to navigate between branches or restore specific file states. While modern versions of Git encourage 'git restore' for files, 'git reset --hard' should be used with extreme caution because it is the most common way to accidentally destroy progress in a Git repository.

Scenario: You have pushed several commits to a shared remote branch, but realize the second-to-last commit introduced a major bug. How do you resolve this?

Because you have already pushed, you should not use 'git reset' to rewrite history, as this would break the branch for everyone else. Instead, the correct professional approach is to use 'git revert <commit-hash>' on that specific buggy commit. This creates a new 'revert' commit that negates the faulty changes. You then push this new commit to the remote, maintaining a clear and honest audit trail of exactly when the bug was introduced and when it was fixed.

All Git & GitHub interview questions →

Check yourself

1. You have modified several files and added them to the staging area, but you decide you are not ready to commit them. Which command safely removes these files from the staging area while keeping your changes intact?

  • A.git reset --hard
  • B.git restore --staged <file>
  • C.git revert HEAD
  • D.git checkout -- <file>
Show answer

B. git restore --staged <file>
git restore --staged removes files from the index without affecting working directory changes. Option 0 deletes all work, option 2 creates a new commit, and option 3 is for discarding local changes, not unstaging.

2. Your team is collaborating on a shared repository. You realize the last commit pushed to the server contains a bug. What is the safest way to undo this commit?

  • A.git reset --hard HEAD~1 and force push
  • B.git revert HEAD
  • C.git commit --amend
  • D.git rm -r .
Show answer

B. git revert HEAD
git revert creates a new commit that negates the changes, which is safe for shared repos. Option 0 rewrites history, causing issues for others; option 2 only modifies the last commit locally; option 3 deletes files from the index.

3. You want to completely discard all local changes to tracked files and return your project to the exact state of the last commit. Which command is most appropriate?

  • A.git restore .
  • B.git reset --soft HEAD
  • C.git revert --no-commit HEAD
  • D.git stash pop
Show answer

A. git restore .
git restore . discards working directory changes for tracked files. Option 1 moves the HEAD but keeps files staged; option 2 creates a revert commit; option 3 restores stashed changes, potentially adding more files.

4. If you perform a 'git reset --soft HEAD~1', what happens to the changes from the last commit?

  • A.They are deleted permanently from your computer.
  • B.They are moved to the working directory as modified files.
  • C.They are kept in the staging area (index) ready to be committed again.
  • D.They are automatically pushed back to the remote repository.
Show answer

C. They are kept in the staging area (index) ready to be committed again.
--soft moves the HEAD back one commit while keeping all changes in the staging area. Option 0 describes --hard, option 1 describes --mixed, and option 3 is impossible as reset does not interact with remote pushes.

5. When is it appropriate to use 'git reset --hard'?

  • A.When you want to permanently abandon all uncommitted local work and sync to the HEAD commit.
  • B.When you need to undo a push to a public shared branch.
  • C.When you want to merge two branches together.
  • D.When you want to undo a commit but keep the changes in your staging area.
Show answer

A. When you want to permanently abandon all uncommitted local work and sync to the HEAD commit.
--hard is used to reset the working directory and staging area to match the HEAD commit. It is dangerous because it deletes uncommitted work. Options 1, 2, and 3 involve operations (reverting, merging, soft reset) that serve different purposes.

Take the full Git & GitHub quiz →

← Previousinit, clone, add, commit, status, logNext →Stashing Changes — git stash

Git & GitHub

20 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app