Git toolbox provides multiple unique tools for fixing up mistakes during your development. Commands such as git reset
, git checkout
, and git revert
allow you to undo erroneous changes in your repository.
Because they perform similar operations, it is very easy to mix them up. There are a few guidelines and rules for when each command should and should not be used. Let's take a look!
Be careful! You can't always redo after an undo. This is one of the few areas in Git where you may lose some work if you do it wrong.
Undoing with Git Commands
I will start off by clarifying the main differences between these three commands.
Checkout:
- Use this to move the HEAD pointer to a specific commit or switch between branches.
- It rollbacks any content changes to those of the specific commit.
- This will not make changes to the commit history.
- Has potential to overwrite files in the working directory.
Revert:
- Rollback changes you have committed.
- Creates a new commit from a specified commit by inverting it. Hence, adds a new commit history to the project, but it does not modify the existing one.
- Has the potential to overwrite files in the working directory.
Reset:
- Use this to return the entire working tree to the last committed state. This will discard commits in a private branch or throw away uncommitted changes!
- Changes which commit a branch HEAD is currently pointing at. It alters the existing commit history.
- Can be used to unstage a file.
Every command lets you undo some kind of change in your repository, only checkout and reset can be used to manipulate either commits or individual files.
Using the Commands
There are many different ways you can undo your changes, it all depends on the current scenario. Selecting an appropriate method depends on whether or not you have committed the change by mistake, and if you have committed it, whether you have shared it or not.
Undo Public Changes
Scenario: Image that you did git push
in hotfix branch for commits you didn't want to make yet.
Solution: The safest way to fix this is by reverting your changes since it doesn't re-write the commit history.
git checkout hotfix
git revert HEAD~1
Result: You have successfully undone committed changes! Everything that was changed in the old commit will be reverted with this new commit. Git forces you to commit or stash any changes in the working directory that will be lost during the checkout.
You can think of
git revert
as a tool for undoing committed changes, whilegit reset HEAD
is for undoing uncommitted changes.
Undo Local Changes
Scenario: You started working on a feature, but you didn't like the end result. These changes haven't been **shared* with anyone else.*
Solution: You want to undo everything in that files to the previous state, just the way it looked in the last commit.
git checkout file_name.rb
Result: File file_name.rb
has been reverted to a state previously known to Git. Note that this removes all of the subsequent changes to the file!
You can use
git checkout branch_name
to switch between branches. Git forces you to commit or stash any changes in the working directory that will be lost during the checkout operation.
Undo Private Changes
Scenario: You've made some commits locally in the hotfix branch but everything is terrible! You want to remove the last two commits from the current branch.
Solution: Reset the hotfix branch backward by two commits as if those commits never happened.
git checkout hotfix
git reset HEAD~2
Result: Your git repository has been rewinded all the way back to the specified commit. Those left out commits are now orphaned and will be removed the next time Git performs a garbage collection. For now, then their contents are still on disk.
You can tell Git what to do with your index (set of files that will become the next commit) and working directory when performing git reset
by using one of the parameters:
-
--soft
: Tells Git to reset HEAD to another commit, so index and the working directory will not be altered in any way. All of the files changed between the original HEAD and the commit will be staged. -
--mixed
: Just like the soft, this will reset HEAD to another commit. It will also reset the index to match it while working directory will not be touched. All the changes will stay in the working directory and appear as modified, but not staged. >The main difference between--mixed
and--soft
is whether or not your index is also modified. Check more on git-reset-guide. -
--hard
: This resets everything - it resets HEAD back to another commit, resets the index to match it, and resets the working directory to match it as well.
Tips and Tricks
There are two additional things that can come in handy during your Git adventures.
Fix the Previous Commit Message
Scenario: Everyone makes typo mistakes when writing commits and this is completely fine! It can be easily fixed before you do a git push
.
Solution: Just run git commit --amend
or git commit --amend -m 'The new message'
. This will update and replace the most recent commit with a new commit.
Redo After Undo
Scenario: You have done a git reset --hard
for some unwanted changes, but then you realized that you actually needed them.
Solution: git reflog
comes to your rescue! It is an amazing command for recovering project history and it can recover almost anything.
Hope this three tools will help you whenever you need to undo your recent changes.
This article is originally published on Kolosek Blog.
Latest comments (3)
Thank you Nesha. What if I just want to take a look at an earlier state of my repository? What's the standard way to just peek at an earlier version? (I don't want to change anything or fix any mistakes). I know it could be done by checking out to an earlier commit but I hear about the dangerous "detached HEAD" state and I felt doubtful whether I have to use it or not? Thanks in advance.
Can also be used to squash commits:
makandracards.com/makandra/527-squ...
Thank you for sharing this useful information! I'll be sure to take a look!