Undoing Changes

One of the most powerful features of Git is the ability to "travel back in time." Whether you've made a simple typo, accidentally deleted a file, or completely broken your codebase with a bad merge, Git provides multiple tools to undo your mistakes.

Understanding which tool to use depends on where your changes are in the Git lifecycle: the Working Directory, the Staging Area, or the Repository.


1. Undoing Changes in the Working Directory

If you've modified files but haven't staged them (git add) yet, you can discard those local changes.

Discarding File Modifications

If you want to revert a file back to its state at the last commit:

# The modern way
git restore filename.txt

# The traditional way
git checkout -- filename.txt

Removing Untracked Files

Sometimes you create new files that you don't want. git clean can sweep them away:

git clean -n    # "Dry run" - shows what would be deleted
git clean -f    # Forcefully delete untracked files
git clean -fd   # Delete untracked files and directories

2. Unstaging Changes (The Staging Area)

If you've run git add but realize you're not ready to commit that specific file yet, you can "unstage" it. This keeps your changes in the file but removes them from the next "snapshot."

# The modern way
git restore --staged filename.txt

# The traditional way
git reset HEAD filename.txt

3. Fixing the Last Commit (--amend)

If you just committed and realized you made a typo in the message or forgot to include a small change, don't create a "fix typo" commit. Use amend instead.

git add forgotten_file.txt
git commit --amend --no-edit   # Fixes the commit without changing the message

4. Resetting History: Moving Back in Time

git reset is a powerful tool that moves your current branch pointer to a previous commit. It has three modes that determine what happens to your work.

git reset --[mode] HEAD~2ABC (HEAD)

The Three Modes of Reset:

  1. --soft: Moves the branch pointer, but keeps all your changes staged. It's like you never committed, but already ran git add.
  2. --mixed (Default): Moves the pointer and unstages your changes, but keeps the files on your disk.
  3. --hard: Moves the pointer and deletes all changes. Your working directory will exactly match the target commit. Use with extreme caution!
git reset --soft HEAD~1    # Undo the last commit, keep changes staged
git reset --hard HEAD~1    # Delete the last commit and all its changes

5. Reverting Shared History (git revert)

The Golden Rule: Never use git reset on commits that you have already pushed to a server (like GitHub). It rewrites history and will break things for your teammates.

Instead, use git revert. This command figures out how to undo the changes from a specific commit and creates a new commit that does the opposite.

Bad CommitRevert Commit

git revert 5b0e43d

This is safe for collaboration because it adds to the history rather than erasing it.


6. The Ultimate Undo: git reflog

What if you ran git reset --hard and realized you deleted work you actually needed? Is it gone forever?

Usually, no. Git keeps a log of every time your HEAD pointer moves. This is called the Reflog.

git reflog

You will see a list of every action you've taken. Find the hash of the commit before your mistake, and you can reset back to it:

git reset --hard <hash-from-reflog>

Summary of Undo Tools

TargetCommandResult
Working Directorygit restore <file>Discards local uncommitted edits.
Staging Areagit restore --staged <file>Unstages a file; keeps the edits.
Last Commitgit commit --amendReplaces the last commit with a new one.
Local Historygit reset --hard <hash>Jumps back in time; deletes newer work.
Public Historygit revert <hash>Adds a new commit that undoes a previous one.
"Lost" Commitsgit reflogRecovers commits that were deleted or rebased.

In the next chapter, we'll dive into Branching, which allows you to work on multiple paths at once without needing to undo as often.