While the purpose of git is to maintain a faithful record of a project’s history, it’s usually not a good idea to blindly include every single change, including mistakes or tiny commits that should be merged into a single one. I’ve written before, about how we can use git squash to keep a clean project, but often it goes beyond even that. Simple things like typos, or accidentally leaving passwords or API keys in code can necessitate the removal of commits.
Fortunately, doing so is easy. Git also has ways to specify how you want to deal with the new data that was committed earlier – you can choose to keep it in staging, out of staging, or delete it altogether. Let’s see how we can do this.
Resetting the Last Git Commit
The command for resetting the last git commit is:
git reset --soft HEAD~1
Below, is a demonstration of how it works. For this example, I’ll assume that we’re setting up a new git project:
mkdir my_project
cd my_project
git init
This creates a new git project in the “my_project” directory. Now let’s create the first file and commit its changes:
echo "Hello World" > file1.txt
git add file1.txt
git commit -m "Add file1.txt with Hello World"
And now let’s make a change to this file and make a second commit:
echo "This is the second line." >> file1.txt
git add file1.txt
git commit -m "Add second line to file1.txt"
Now let’s look at our git log to see what the status is:
git log --oneline
Here’s what I see:
So we see that the git project has two commits – one for each line. Now let’s say we want to revert the second commit so that we go back to the first one. To reset the last commit, we use:
git reset --soft HEAD~1
After running this command, when we check the git log, here is what we see:
You can see that after running the reset command, the HEAD has gone back one step and it’s as if the second commit never happened!
Three Ways of Dealing with Previously Committed Data
In the previous example, while we got rid of the commit, what about the changes to the file that we made? Git gives us three options to deal with them.
–soft
When we use the “–soft” parameter with git, the changes to the files persist. Not only that, the changes are still “staged”. The only difference is that they haven’t been committed. This might seem like a niche use, but it’s surprisingly common because we make typos or poorly worded commits all the time. Or perhaps you want to add more staged files. In such situations, the “–soft” option is best.
–mixed
The “–mixed” option is the default if you don’t specify anything while using the git reset command. Like the “–soft” option, it also keeps the changes to all the files and folders that were uncommitted. However, unlike “–soft”, it removes them from staging as well. Use this option if you want to start over from the staging process entirely.
–hard
The “–hard” option is the nuclear button. It not only removes the changes from both the commit and the staging area but also erases all the changes to the files as well! That is, it actively modifies the files in your project and restores them to what they were like just after the last commit. This means that you lose everything on which you worked since the last commit.
Naturally, you want to use this last option very carefully. Only do it when you’re sure you want to start over from scratch and erase all the work you’ve done since the last commit.
Understanding What the “HEAD” is in Git
A git project is a series of commits and each commit can branch out into a new direction. The HEAD always points to the latest commit in any branch. When you work on a new branch, the HEAD moves to the last commit made in that branch. The only time that’s not the case is when you make something called a “detached commit”, but that’s a topic for a different article.
Because of this property of always pointing to the latest commit, when you move the head the previous one, it’s as good as undoing the last commit.
Getting Back the Lost Commit
As we’ve seen above, resetting the HEAD with either the “–soft” or “–mixed” option allows you to preserve your changes in either the staging area or just in the files. It means you can recommit your changes with a slightly different commit message, or make further changes to the files. But if you use the “–hard” option, then the files are returned to the previous state before the latest commit. This means that you lose everything.
However, there are two ways to “get back” the changes lost during a hard reset. You shouldn’t rely on these because you never know what will go wrong, but in case of emergency, you can see if these work.
Getting the Commit from the Remote Branch
Before you reset the HEAD, you might have pushed your changes to the remote branch. Because git only works on the local copy of your company unless you explicitly push it with a command, when you reset the HEAD, you only lose the commit changes on your local branch. But before you reset the HEAD, if you had already pushed your project to the remote branch, it would persist, and can get back the lost changes by rechecking the remote branch.
Using Git Reflog
Another way to see the lost changes is to use a tool like “git reflog”. The command is:
git reflog
This will show you the various commits along with the changes those commits made. The best part is that it gives you the commit SHA, which is like a pointer to the actual commits. Here’s what it looks like:
You can see the commit SHAs in red. Then, you can try restoring the commits using something like this:
git checkout <commit-sha>
This will bring the git HEAD to the commit in a “detached” state. You can even re-commit the lost commit using the following command:
git cherry-pick <commit-sha>
And you can also reset to the specific commit like this:
git reset --hard <commit-sha>
All the above methods can be used to try and recover a lost commit due to a reset. As you can see, it’s not easy to completely remove all the evidence from your git history!
Benefits of Resetting the Last Commit
It might seem like a niche use of the “git reset” command, but there are often good reasons to reset a commit like this.
For example, one reason is that you simply made a typo in the commit and need to reset it so that you can commit it again with the corrected commit message. Sometimes, you might make a mistake and commit sensitive information like an API key or a password to a git commit. You can rectify this by resetting the git commit, removing the offending information, and recommitting it.
Conclusion
As you can see, resetting a git commit is very easy. Ensure you don’t lose your changes when you don’t mean to!
I’m a NameHero team member, and an expert on WordPress and web hosting. I’ve been in this industry since 2008. I’ve also developed apps on Android and have written extensive tutorials on managing Linux servers. You can contact me on my website WP-Tweaks.com!
Rom says
Great tutorial! The explanations on resetting the last commit in Git are clear and easy to follow. I especially appreciate the breakdown of –soft, –mixed, and –hard reset options, which helps in understanding the potential effects each one has on the working directory and index. A quick addition on how to handle cases where the last commit has already been pushed would make it even more comprehensive. Thanks for sharing!