← Recipes

阅读中文版本

Undo a Bad Commit with git revert

Undo a commit on a shared branch by creating a new inverse commit, preserving history and avoiding the disruption of a force-push.

~10 mingitversion-controlrecovery

Task

Reverse the effect of a specific commit that is already pushed to a shared branch without rewriting history.

When to use this

A buggy change reached main and other developers have pulled it. You need to restore the previous behavior while keeping an auditable record.

Prerequisites

  • The hash of the commit to undo
  • A clean working tree or a stash of local changes
  • Permission to push to the shared branch

Steps

1. Identify the exact commit and confirm it contains the change you intend to undo.

git log --oneline -10

Expected output: The target commit hash and message are visible.

2. Create an inverse commit. Use --no-commit when several commits must be reverted together or when conflicts need editing.

git revert --no-edit <commit-sha>

Expected output: A new commit is created that reverses the target change.

3. Run the relevant tests and review the diff to confirm only the intended behavior changed.

git show --stat HEAD && npm test

Expected output: Tests pass and the diff matches the reverted change.

4. Push the revert commit normally. Do not force-push a shared branch for a revert.

git push origin main

Expected output: The branch advances with an additional revert commit.

Troubleshooting

Problem

Revert reports conflicts

Solution

Resolve the files, stage them, then run git revert --continue. The conflict usually means later commits depend on the reverted code.

Problem

The change was a merge commit

Solution

Use git revert -m 1 <merge-sha> and verify which parent represents the mainline.

Limitations

  • Reverting does not fix the root cause; open a follow-up change with the corrected implementation.
  • A revert restores behavior but leaves the original commit in history, which may be undesirable for security incidents.

Why revert instead of reset

git reset --hard rewrites branch history and forces every collaborator to recover. git revert adds a new commit that undoes the target change, so the branch remains append-only and the audit trail shows both the mistake and its correction.

git log --oneline -5
git revert --no-edit 4f3c2a1
git push origin main

For a merge commit, select the mainline parent explicitly:

git revert -m 1 <merge-commit-sha>

Verify

  • git log shows a new Revert "..." commit after the original.
  • The files changed by the original commit are restored to their previous content.
  • The test suite passes on the reverted branch.
  • git status is clean and the remote branch contains both commits.

When to use reset instead

Use reset only for local, unpushed commits or on a branch no one else uses. If the goal is to remove sensitive data rather than behavior, history rewriting plus credential rotation is required; a revert alone does not remove the data.