February 13, 2025
O. Wolfson
Working with Git can sometimes lead to mistakes like unwanted changes or lost commits. Fortunately, Git offers robust tools to revert changes and recover lost work. This article will guide you through key commands for undoing changes and reverting to previous states.
Three commands are often used to undo changes and recover lost work:
Each command has different purposes and behaviors.
Command | Purpose | Affects Working Directory? | Affects Staging Area (Index)? | Affects Commit History? | Common Use Case |
---|---|---|---|---|---|
git restore | Restore file(s) to a previous state | Yes (optional) | Yes (optional) | No | Discard changes in the working directory or unstage changes |
git reset | Move HEAD and optionally update index and working directory | Optional | Yes | Yes (in some modes) | Unstage changes, discard commits, or move HEAD |
git revert | Create a new commit that undoes a previous commit | No | No |
git restore
Examples:
bashgit restore file.txt # Discard changes in working directory (reverts to last committed state)
git restore --staged file.txt # Unstage file but keep changes in working directory
git restore --source=HEAD~1 file.txt # Restore file to state from one commit ago
git reset
--soft
: Moves HEAD, keeps changes staged.--mixed
(default): Moves HEAD, unstages changes, keeps working directory.--hard
: Moves HEAD, unstages and discards changes in working directory.Examples:
bashgit reset --soft HEAD~1 # Undo last commit, keep changes staged
git reset --mixed HEAD~1 # Undo last commit, unstage changes, keep working directory
git reset --hard HEAD~1 # Undo last commit, discard changes from working directory
git revert
Examples:
bashgit revert HEAD # Revert last commit (create a new commit that undoes it)
git revert <commit-hash> # Revert a specific commit
Feature | git restore | git reset | git revert |
---|---|---|---|
Undo Working Directory Changes | ✔️ | ✔️ (with --hard ) | ❌ |
Unstage Files | ✔️ | ✔️ | ❌ |
Undo Commits | ❌ |
Situation | Recommended Command |
---|---|
Discard changes in working directory | git restore file.txt |
Unstage a file | git restore --staged file.txt |
Undo the last commit, keep changes staged | git reset --soft HEAD~1 |
Undo the last commit, keep changes in working directory | git reset --mixed HEAD~1 |
Undo the last commit, discard changes entirely |
Building on the project we created earlier called my_git_project
. Let’s continue using this project to simulate common scenarios, like accidental deletions, bad commits, and recovery, so you can learn how to get back on track when things go wrong.
my_git_project
If you haven’t already, follow these steps to create a simple project:
bashmkdir my_git_project
cd my_git_project
git init
Create and commit a file:
bashecho "Hello, Git!" > hello.txt
git add hello.txt
git commit -m "Added hello.txt with a greeting message"
Make a second change:
bashecho "Welcome to version control." >> hello.txt
git add hello.txt
git commit -m "Updated hello.txt with an additional message"
Now, we have a small history to work with.
Let’s say you realize that the second commit was a mistake. You want to go back to the first version.
You can view the state of the project at the initial commit without changing your branch:
Get the commit hash for the initial commit:
bashgit log --oneline
Example output:
text9e2b4d2 Updated hello.txt with an additional message 4f6b3c2 Added hello.txt with a greeting message
Temporarily switch to the first commit:
bashgit checkout 4f6b3c2
You are now in "detached HEAD" state, viewing the project as it was at the initial commit. To return to the latest state:
bashgit checkout main
If you want to undo the second commit and erase it from history:
bashgit reset --hard 4f6b3c2
This will delete the second commit and any changes after it. Use this with caution—it’s permanent!
Instead of erasing history, you can undo the effects of a specific commit by creating a new commit:
bashgit revert 9e2b4d2
This will create a new commit that undoes the changes made in the second commit. The history remains intact, which is safer for shared projects.
Sometimes, you need to undo recent work without deleting your progress.
Let’s say you committed changes, but realized you forgot to add something. You can undo the last commit while keeping your changes staged:
bashgit reset --soft HEAD~1
This moves the commit back, but your changes stay in the staging area. You can modify files and commit again.
If you want to completely remove the last commit and all changes:
bashgit reset --hard HEAD~1
This is irreversible—use with care.
If you made changes to hello.txt
but want to discard them:
bashgit restore hello.txt
This reverts the file to the last committed state. To discard all files:
bashgit restore .
git reflog
What if you made a hard reset and realize you lost important work?
bashgit reflog
Example output:
text3f9d2a1 HEAD@{0}: reset: moving to HEAD~1 9e2b4d2 HEAD@{1}: commit: Updated hello.txt with an additional message 4f6b3c2 HEAD@{2}: commit: Added hello.txt with a greeting message
Find the lost commit (e.g., 9e2b4d2
), and recover it:
bashgit checkout 9e2b4d2
Save it by creating a new branch:
bashgit branch recovered-work
Switch to this branch:
bashgit checkout recovered-work
This brings your lost work back into the project.
my_git_project
.hello.txt
:
bashecho "Oops, this might be a mistake." >> hello.txt
git add hello.txt
git commit -m "Added a potentially bad line"
bashgit reset --hard HEAD~1
git reflog
to find the commit hash.bashgit checkout <commit_hash>
bashgit branch recovered-work git checkout recovered-work
This exercise teaches you that even when things seem lost, git reflog
is your safety net.
Command | Purpose |
---|---|
git checkout <commit> | Temporarily view an old commit. |
git reset --hard <commit> | Permanently move branch to a previous commit (destructive). |
git revert <commit> | Create a new commit to undo a previous commit (safe). |
git reset --soft HEAD~1 | Undo last commit but keep changes staged. |
git reset --hard HEAD~1 | Undo last commit and discard changes. |
Mistakes are part of development. Knowing how to undo changes and recover lost work will boost your confidence in using Git. Experiment with these commands in my_git_project
to get comfortable before working on larger projects.
Yes |
Safely undo a commit in public history |
✔️ (moves HEAD) |
✔️ (creates new commit) |
Preserves History | ✔️ | ❌ (except --soft ) | ✔️ |
Safe for Public History | ✔️ | ❌ | ✔️ |
git reset --hard HEAD~1
Undo a specific commit safely in shared history | git revert <commit> |
git restore <file> | Discard changes in a file. |
git reflog | View the history of HEAD movements to recover lost commits. |