Git: Revert to a Previous Commit

If I've learned anything in my 15+ years of programming, it's that mistakes are common, and I make a lot of them. This equally applies to version control tools as well. Whether you accidentally commit changes, or just realized your previous committed code isn't what you wanted, oftentimes you'll need to revert a previous commit in Git.

In this article I'll show a few ways to revert your commits, depending on your use-case. This is a complicated topic (which is true for many Git topics in general), so make sure you follow the instructions that best suit your needs.

Delete Unpublished Commits

If you haven't yet published your commits to a remote repository, like GitHub, then you can essentially delete previous commits by using the reset command.

While this is an effective solution, it's a dangerous one since you're rewriting history and leaving the "deleted" commits unreferenced, or "orphaned". The only way to find and recover these unreferenced commits is with git reflog.

The reset command has three different options, two of which we'll describe here:

$ git reset --hard <hash-or-ref>

Using the --hard option, everything is reverted back to the specific commit. This includes the commit history reference pointers, the staging index, and your working directory.

This means that by using just this command you'll not only revert to a previous commit, but you'll lose all working changes in the process. To avoid losing any working changes, you can use the stash and stash pop commands:

$ git stash
$ git reset --hard <hash-or-ref>
$ git stash pop

The stash command saves your working changes (without any commits or changes to the tree), and then stash pop brings them back.

The other option you may consider is the --soft option. This option works much the same way as git reset --hard <hash-or-ref>, but it only affects the commit history, not your working directory or staging index.

$ git reset --soft <hash-or-ref>

So if you have uncommitted changes that you want to keep, then this is likely the option you want.

Deleting Published Commits

So let's say you committed your code and then pushed it to the remote repository. At this point it's highly advised that you do not use something like git reset since you'd be rewriting history.

Instead, the recommended approach would be to use the revert command. This command works by undoing changes that were made in the specific commit by creating a new commit and not actually removing any previous commits. This is ideal for published changes because then the true history of the repo is preserved. Here is the command:

$ git revert <hash-or-ref>

So let's say you have a text file in your repo with the following content:

This is my sample text

And then you change it to:

This is my awesome sample text

Your commit history might look something like this:

$ git log --pretty=oneline
676ec97a9cb2cebbb5c77904bbc61ced05b86f52 Added 'awesome' to text
735c5b43bf4b5b7107a9cc3f6614a3890e2889f6 Initial commit

If we decide we don't want "awesome" in our text anymore, but we don't want to delete the 676ec commit, we can use revert to undo that change:

$ git revert 676ec
[master f68e546] Revert "Added 'awesome' to text"
 1 file changed, 1 insertion(+), 1 deletion(-)
Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

After being prompted to enter a commit message, we can now see in our commit history that there is actually a new commit:

$ git log --pretty=oneline
f68e546ac2ae240f22b2676b5aec499aab27f1ca Revert "Added 'awesome' to text"
676ec97a9cb2cebbb5c77904bbc61ced05b86f52 Added 'awesome' to text
735c5b43bf4b5b7107a9cc3f6614a3890e2889f6 Initial commit

As a result of this, the first and third commits represent the exact same project state. The commit has been reverted, and no history was lost.

Note that there are quite a few other ways to use this command, like if you want to revert back 2 commits, you can use:

$ git revert HEAD~2

Or if you want to revert many non-continuous commits you specify them individually:

$ git revert 676ec 735c5

Cherry-Picking a Commit

In Git, "cherry-picking" refers to the process of applying a specific commit from one branch to another. This allows you to selectively apply changes made in the past without affecting the current state of the repository.

To cherry-pick a commit, first identify the commit hash of the commit you want to apply. You can do this by running the git log command and looking for the hash of the commit you want to cherry-pick.

Once you have identified the commit hash, switch to the branch you want to apply the changes to, and run the following command:

$ git cherry-pick <commit-hash>

This will apply the changes made in the specified commit to the current branch, creating a new commit that contains only those changes. If the changes conflict with the current state of the branch, Git will prompt you to resolve the conflicts before continuing.

It's important to note that cherry-picking a commit does not merge the entire branch that the commit is on. It only applies the changes made in the specified commit. This can be useful if you want to apply a specific fix or feature from one branch to another without merging the entire branch.

Cherry-picking a commit can also be used to revert changes made in a previous commit. To do this, simply cherry-pick the commit you want to revert, and then apply the changes to the current branch. This will create a new commit that undoes the changes made in the original commit.

Temporarily Checkout a Previous Commit

By "reverting a commit", you might mean that you temporarily want to go back to a previous state in your repo, but without making any actual changes to the tree. In this case you'd probably just want to checkout the commit, allowing you to go back to master or any other state when you're done:

$ git checkout <hash-or-ref>

This will change your working directory to the contents of that commit, as well as the location HEAD points to, none of which is irreversible. Any changes you make here can either be committed to a branch or stashed for later use.

Last Updated: February 16th, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

© 2013-2024 Stack Abuse. All rights reserved.