How do I reverse a commit in git?

Learn how do i reverse a commit in git? with practical examples, diagrams, and best practices. Covers git, github, commit development techniques with visual explanations.

How to Reverse a Commit in Git: A Comprehensive Guide

Hero image for How do I reverse a commit in git?

Learn the essential Git commands to undo or revert commits, understanding the differences between git revert and git reset for safe and effective version control.

Accidentally committing changes, introducing bugs, or pushing sensitive information are common scenarios in software development. Fortunately, Git provides powerful tools to reverse commits and manage your project's history. This article will guide you through the primary methods for undoing commits: git revert and git reset, explaining when and how to use each effectively.

Understanding Git's Immutability and Reversals

Git's core strength lies in its immutable commit history. Once a commit is made, it's permanently recorded. When we talk about 'reversing' a commit, we're not actually deleting it from history (unless using advanced, destructive methods). Instead, we're either creating a new commit that undoes the changes of a previous one, or moving the branch pointer to an earlier state, effectively making subsequent commits unreachable from that branch.

flowchart TD
    A[Commit A] --> B[Commit B]
    B --> C[Commit C (Error Introduced)]
    C --> D[Commit D]

    subgraph Revert
        C -- "git revert C" --> E[Commit E (Undoes C)]
    end

    subgraph Reset
        D -- "git reset --hard B" --> B
    end

    E --> F[New History with Revert]
    B --> G[New History with Reset]

    style Revert fill:#f9f,stroke:#333,stroke-width:2px
    style Reset fill:#ccf,stroke:#333,stroke-width:2px

Conceptual difference between git revert and git reset

Method 1: git revert (The Safe Way)

git revert is the safest and most recommended way to undo changes, especially on shared branches. Instead of deleting history, it creates a new commit that undoes the changes introduced by a specified commit. This means the original commit remains in the project history, and the revert commit explicitly states that its purpose is to undo previous work.

1. Identify the Commit

First, you need to find the hash of the commit you want to revert. You can use git log to view your commit history.

2. Perform the Revert

Once you have the commit hash (e.g., abcdef1), execute the git revert command. Git will open your default editor to allow you to modify the commit message for the new revert commit. Save and close the editor to complete the revert.

3. Push the Changes

After reverting, you'll have a new commit in your local history. Push this commit to your remote repository as you would any other new commit.

git log --oneline
# Example output:
# abcdef1 My faulty commit
# 1234567 Another feature
# fedcba9 Initial commit

git revert abcdef1
# Git will open an editor for the commit message. Save and close.

git push origin <your-branch-name>

Reverting a commit and pushing the changes

Method 2: git reset (The Powerful, Potentially Dangerous Way)

git reset is a more powerful command that rewrites history by moving the HEAD pointer and optionally changing the staging area and working directory. It's generally used for local, unpushed commits, as rewriting shared history can lead to conflicts and lost work for collaborators.

Types of git reset

There are three main modes for git reset:

Soft Reset

Moves HEAD to the specified commit, but keeps the changes from the reset commits in your staging area (index). This is useful if you want to combine several commits into one or re-commit with a different message.

git reset --soft HEAD~1
# HEAD~1 refers to the commit immediately before HEAD
# You can also use a specific commit hash: git reset --soft <commit-hash>

Mixed Reset (Default)

Moves HEAD to the specified commit and unstages the changes from the reset commits, but keeps them in your working directory. This is the default behavior if no flag is provided. It's useful for undoing a commit and then re-staging and re-committing parts of it.

git reset HEAD~1
# Or: git reset --mixed HEAD~1
# Changes are now in your working directory, ready to be re-staged.

Hard Reset

Moves HEAD to the specified commit, and discards all changes from the reset commits from both the staging area and the working directory. This is the most destructive option and should be used with extreme caution, as it permanently deletes uncommitted changes.

git reset --hard HEAD~1
# All changes from the last commit are gone from your working directory.
# Use with extreme care!

When to Use Which Method

Choosing between git revert and git reset depends heavily on whether the commit has been shared with others and the desired outcome.

Hero image for How do I reverse a commit in git?

Comparison of git revert vs. git reset

In summary:

  • git revert: Use when you need to undo changes that have already been pushed to a shared remote repository. It creates a new commit, preserving history and avoiding conflicts for collaborators.
  • git reset: Use for local, unpushed commits to clean up your commit history before sharing. git reset --soft and --mixed allow you to retain changes for re-committing, while git reset --hard permanently discards them.
git reflog
# Example output:
# abcdef1 HEAD@{0}: reset: moving to HEAD~1
# 1234567 HEAD@{1}: commit: My faulty commit
# fedcba9 HEAD@{2}: commit (initial): Initial commit

git reset --hard 1234567
# This would restore the 'My faulty commit' and its changes.

Using git reflog to recover from a git reset --hard