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.
The Three Modes of Reset:
--soft: Moves the branch pointer, but keeps all your changes staged. It's like you never committed, but already rangit add.--mixed(Default): Moves the pointer and unstages your changes, but keeps the files on your disk.--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.
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
| Target | Command | Result |
|---|---|---|
| Working Directory | git restore <file> | Discards local uncommitted edits. |
| Staging Area | git restore --staged <file> | Unstages a file; keeps the edits. |
| Last Commit | git commit --amend | Replaces the last commit with a new one. |
| Local History | git reset --hard <hash> | Jumps back in time; deletes newer work. |
| Public History | git revert <hash> | Adds a new commit that undoes a previous one. |
| "Lost" Commits | git reflog | Recovers 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.