One of the key advantages of Git is its ability to allow you to undo changes at various stages of your workflow. Whether you made a simple mistake in the staging area, committed something too early, or need to revert an entire feature branch, Git has powerful mechanisms to recover and fix mistakes.
In this chapter, we will explore how to undo changes in Git from the most basic to the most advanced operations. By the end of this section, you will have mastered everything from unstaging files to rewriting history.
Undoing changes in Git is essential in many situations:
Understanding how to safely undo changes ensures that mistakes are handled efficiently without affecting the progress of your project.
Let’s say you’ve staged a file but realized it wasn’t supposed to be added to the next commit. You can “unstage” a file using the git restore
command.
$ git add myfile.txt
$ git restore --staged myfile.txt
git add
command stages myfile.txt
for the next commit.git restore --staged
removes the file from the staging area, but it doesn’t delete the changes from the working directory.If you’ve modified a file but want to discard the changes and return it to the last committed version:
$ git restore myfile.txt
This command discards any uncommitted changes to the file and restores it to the state from the last commit.
$ echo "New changes" > myfile.txt
$ git restore myfile.txt
After running this command, myfile.txt
will revert to the version from the latest commit, discarding any new modifications.
Sometimes, you realize you’ve made a mistake right after committing changes. Git provides multiple ways to handle this depending on the situation.
If you’ve committed but want to modify the commit (e.g., you forgot to add a file or want to change the commit message), you can use the --amend
option.
$ git commit -m "Initial commit"
$ git add forgottenfile.txt
$ git commit --amend
This command does the following:
forgottenfile.txt
) with the previous commit.After running git commit --amend
, Git will replace the previous commit with a new one, and your commit history will be rewritten.
If you want to undo the last commit but keep your changes in the working directory, use git reset
with the --soft
option:
$ git reset --soft HEAD~1
This moves the HEAD pointer back by one commit, effectively “undoing” the last commit. However, the changes remain staged.
If you want to completely remove the last commit and discard its changes, use:
$ git reset --hard HEAD~1
The --hard
option resets both the commit history and the working directory to the previous commit. Be cautious with this command, as changes will be lost.
The git reset
command is a powerful tool for undoing commits and controlling which changes are kept or discarded. There are three levels of reset: --soft
, --mixed
, and --hard
.
Let’s break down the options:
--soft
: Moves the HEAD pointer to the previous commit but leaves all changes in the staging area.--mixed
(default): Moves the HEAD pointer to the previous commit, removes changes from the staging area, but keeps them in the working directory.--hard
: Moves the HEAD pointer to the previous commit and removes all changes from both the staging area and the working directory.Suppose you have the following commit history:
A---B---C (HEAD)
To reset the branch back to commit B
:
$ git reset --soft B
The result:
A---B (HEAD)
The changes from commit C
will remain staged.
You can also reset multiple commits at once. If you’ve made several erroneous commits, you can reset to an earlier point in the history:
$ git reset --hard HEAD~3
This moves the branch pointer back three commits and discards all changes introduced by those commits.
Unlike git reset
, which rewrites history, git revert
creates a new commit that undoes the changes introduced by a previous commit. This is a safer option in collaborative environments because it preserves the commit history.
If you want to undo the changes made by a specific commit:
$ git revert
This creates a new commit that negates the changes made in the specified commit.
Example:
$ git revert 3a5b7c2
Git will open an editor allowing you to write a commit message for the revert commit.
You can revert a range of commits as well:
$ git revert HEAD~3..HEAD
This command reverts the last three commits, creating individual revert commits for each.
In older versions of Git, git checkout
was used for undoing changes, but it’s now replaced by git restore
for many use cases. However, you can still use checkout
to undo changes to entire branches.
To switch your working directory to a previous commit (without modifying your branch’s history):
$ git checkout
While this detaches the HEAD (puts you in a “detached HEAD” state), it allows you to explore an older version of your project without making any changes to your current branch.
$ git checkout 5d41402
Your working directory will reflect the state of the project at that specific commit.
If you’ve made changes in your working directory that you don’t want to keep, you can reset your directory to match the latest commit:
$ git checkout -- .
This command discards all uncommitted changes in your working directory.
Sometimes, you want to save changes without committing them, for example, when you need to switch branches but don’t want to commit incomplete work. git stash
allows you to temporarily store your modifications.
To stash your changes:
$ git stash
Your working directory is reset to the last commit, and the changes are saved in the stash stack.
Later, when you’re ready to reapply the stashed changes:
$ git stash apply
This applies the most recent stash to your working directory without removing it from the stash list.
To identify your stashes more easily, you can provide a message:
$ git stash save "WIP: refactor header"
To see all stashes:
$ git stash list
Once you no longer need a stash, you can delete it:
$ git stash drop
Sometimes you may delete a branch or reset your repository, thinking certain commits are gone forever. Fortunately, Git keeps track of many actions, and you can recover lost commits or branches.
If you accidentally delete a branch:
$ git branch -d feature
You can recover it as long as you know the commit hash:
$ git checkout -b feature
git reflog
to Recover CommitsGit maintains a history of every action performed, which can be accessed using git reflog
. This is extremely helpful when trying to recover a lost commit or branch.
To view the reflog:
$ git reflog
You can use this to recover a lost commit:
$ git checkout
In Git, the ability to undo changes is an essential part of managing and maintaining a clean, efficient workflow. Whether you're dealing with minor mistakes like staging the wrong file or more significant challenges like recovering deleted commits or branches, Git offers various commands to address these situations. From simple commands like git restore to manage files, to more complex operations like git reset, git revert, and git reflog, you have powerful tools at your disposal to correct mistakes and keep your project history intact. Happy coding !❤️