We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

Git Revert: Undo Commits Without Rewriting History

ThePrimeagen
ThePrimeagenEx-Netflix engineer, NeoVim ricer, and Git rebaser

Last published

Table of Contents

Sometimes you need to undo a commit that's already on a shared branch. You could reach for git reset, but resetting rewrites history, and rewriting shared history is a great way to ruin your coworkers' day. git revert undoes a commit the polite way: by adding a new commit that reverses the old one. Nothing gets deleted, history stays intact, and nobody wants you dead.

All the content from our Boot.dev courses are available for free here on the blog. This one is the "Revert" chapter of Learn Git 2. If you want to try the far more immersive version of the course, do check it out!

What Does Git Revert Actually Do?

Where git reset is a sledgehammer, git revert is a scalpel.

A revert is effectively an anti commit. It does not remove the commit (like reset), but instead creates a new commit that does the exact opposite of the commit being reverted. It undoes the change but keeps a full history of the change and its undoing.

A - B - C        before revert
A - B - C - C'   after "git revert C"

C' contains the inverse of C's changes. Both commits stay in the log forever, which is exactly what you want on a branch other people are pulling from. If you're curious how commits are stored under the hood (and why deleting them is such a big deal), read Git Internals.

How Do You Revert a Commit?

To revert a commit, you need to know the commit hash of the commit you want to revert. You can find this hash using git log.

git log --oneline
# e3f4d5a add real marketing copy
# a1b2c3d claim product uses blockchain AI
# 9f8e7d6 initial commit

Here, the "blockchain AI" claim is the commit that needs to go. Once you have its hash, you can revert it with git revert:

git revert a1b2c3d

Git will prompt you to write a commit message for the new revert commit. The default is usually fine:

Revert "claim product uses blockchain AI"

This reverts commit a1b2c3d.

To revert the most recent commit, you don't even need the hash, just use HEAD:

git revert HEAD

Reverting to a Previous Commit

The top Google search for revert is "git revert to previous commit", and it's a bit of a trap: people usually mean one of two very different things.

If you want to undo the changes from the last few commits while keeping history intact, you can revert a range. This creates one anti-commit for each commit in the range, newest first:

git revert a1b2c3d..HEAD

If you want your branch to become an older commit, throwing away everything after it, that's not a revert at all, that's git reset --hard. It's the right tool on a private branch and a terrible one on a shared branch. And if you screw up a hard reset, don't panic, git reflog can usually bail you out.

Checking Your Work With Git Diff

The git diff command shows you the differences between... stuff. Differences between commits, the working tree, etc.

I frequently use it to look at the changes between the current state of my code and the last commit:

git diff

You can also diff against an older commit, or between any two commits:

git diff HEAD~1
git diff COMMIT_HASH_1 COMMIT_HASH_2

That last form is perfect for sanity-checking a revert. If the revert commit lands directly on top of the commit it undoes, diffing the two shows the exact same change, just backwards: every + line becomes a - line and vice versa. And if the diff between the commit before the original and the revert commit is empty, the undo was perfect.

Git Revert vs Git Reset: Which Should You Use?

Click to play video

Here's the cheat sheet:

Command What it does Rewrites history?
git reset --soft Undo commits but keep changes staged Yes
git reset --hard Undo commits and discard changes Yes
git revert Create a new commit that undoes a previous one No

If you're working on your own branch, and you're just undoing something you've already committed, say you're cleaning everything up so you can open a pull request, then git reset is probably what you want. The same goes for other history-rewriting cleanup like rebasing or squashing commits: totally fine on your own private branch.

However, if you want to undo a change that's already on a shared branch (especially if it's an older change), then git revert is the safer option. It won't rewrite any history, and therefore won't step on your coworkers' toes.

Fun fact: git revert is kinda a sibling to git cherry-pick. Cherry-pick takes a commit from somewhere else and applies its changes; revert takes a commit you already have and applies its changes in reverse.

If reset, branches, or commit history still feel shaky, the Learn Git course covers the fundamentals, and Learn Git 2 picks up from there with reverts, reflog, bisect, and the rest of the "oh no, how do I fix this" toolkit.

Frequently Asked Questions

Does git revert delete the commit?

No. git revert creates a new commit that reverses the changes of the target commit. Both the original commit and the revert commit stay in the history.

What is the difference between git revert and git reset?

git reset moves your branch pointer and removes commits from history, while git revert adds a new commit that undoes a previous one. Revert is safer on shared branches because it never rewrites history.

How do I revert the most recent commit?

Run git revert HEAD. Git creates a new commit that undoes the changes from the latest commit.

Can I revert multiple commits at once?

Yes. Pass a range like git revert <older-hash>..HEAD and Git creates one revert commit for each commit in the range, starting with the newest.

Is git revert safe on shared branches?

Yes, that is its main advantage. Because revert only adds new commits and never rewrites existing history, it will not break anyone else's copy of the branch.

Related Articles