Git Revert: A Safe Way to Remove Faulty Commits

gauraws

Gaurav Singh

Posted on September 29, 2024

Git Revert: A Safe Way to Remove Faulty Commits

Have you ever faced a situation where you had to undo changes in the master branch because some unwanted code was committed, potentially leading to production bugs?

Well, we faced a similar issue in our project when a developer accidentally cherry-picked a commit that wasn’t tested and deployed it to production. Luckily, our app is an in-house product used by the company itself, so the impact was minimal.

Such cases can happen when you have a distributed team spread across a few countries and different time zones. Here's how we removed a particular commit from our master (production) branch and resolved the issue quickly.

Git revert to the rescue.
git revert is used to create new commits that reverse the effects of earlier commits (often just a faulty one).

The git revert command can be considered an "undo" type of command, but it is not a traditional undo operation. Instead of removing the commit from the project history, it inverts the changes introduced by the commit and appends a new commit with the resulting inverse content. This prevents Git from losing history, which is crucial for the integrity of your revision history and for reliable collaboration.

In simple terms, git revert is used to undo a commit (say hash 2afe34), but it does so by creating a new commit that removes the changes from the commit (2afe34) you are reverting.

For example, if you’re tracking down a bug and find that it was introduced by a single commit, instead of manually fixing it and committing a new change, you can use git revert to automatically handle this for you.

Syntax:
git revert [--options] <commit>

git revert takes a specified commit from the history, inverts the changes from that commit, and creates a new "revert commit."

Let's demo it:
I have this index.html file I created for demo purposes. It contains an ordered list of fruits. Below are my commits with the changes made in each one:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Fruits</title>
</head>
<body>
    <div>
        <h3>Fruits list</h3>
        <ol>
            <li>Mango</li>
            <li>Orange</li>
            <li>Banana</li>
        </ol>
        <h3>Other list</h3>
        <ul>
            <li>Apple</li>
            <li>Pineapple</li>
        </ul>
    </div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
7afe5e3 (HEAD -> master) add other list
c8862d9 add banana
8db1cd2 add orange
f4e9e1f add mango
065a354 initial commit
Enter fullscreen mode Exit fullscreen mode

My first commit is an initial commit with just the basic HTML structure like head and body. Rest commits are self explanatory. I added mango in commit f4e9e1f, orange in 8db1cd2, and banana in c8862d9 inside the first ordered list (<ol>). I then added a second ordered list with more items in commit 7afe5e3, which is the current HEAD commit.

Let’s say I want to remove banana from the list. In this simple example, we could just remove banana from the code and create a new commit reflecting that change.

However, in a collaborative project with multiple contributors, commit history becomes important to track the project's state at any given point in time. Moreover, manually undoing large code changes wouldn’t be feasible, and git revert becomes an inevitable solution.

Going back to our demo, to remove banana from the first ordered list, I can simply run git revert c8862d9 and this creates a new commit explaining the reason for the revert. You’ll see that banana is now removed from the list.

So new index file and commit history will look like below:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fruits</title>
</head>
<body>
    <div>
        <h3>Fruits list</h3>
        <ol>
            <li>Mango</li>
            <li>Orange</li>
        </ol>
        <h3>Other list</h3>
        <ul>
            <li>Apple</li>
            <li>Pineapple</li>
        </ul>
    </div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Commit history after git revert: git log --oneline

828ef17 (HEAD -> master) Revert "add banana"
7afe5e3 add other list
c8862d9 add banana
8db1cd2 add orange
f4e9e1f add mango
065a354 initial commit
Enter fullscreen mode Exit fullscreen mode

Sometimes, Git is not smart enough to figure out the exact code that needs to be removed, leading to merge conflicts. In these cases, you, as a developer, need to help Git a bit.

It’s important to understand that git revert undoes a single commit—it does not "revert" the project to a previous state by removing all subsequent commits like git reset.

Reverting has two important advantages over resetting:

  1. It doesn’t change the project history, making it a “safe” operation for commits that have already been published to a shared repository.

  2. git revert can target an individual commit at any arbitrary point in the history.

Happy coding! 😊

💖 💪 🙅 🚩
gauraws
Gaurav Singh

Posted on September 29, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Git Revert: A Safe Way to Remove Faulty Commits
productivity Git Revert: A Safe Way to Remove Faulty Commits

September 29, 2024

What is etcd ? Kubernetes bitesize
kubernetes What is etcd ? Kubernetes bitesize

November 10, 2019