GIT – Revert?

Most of the blogs I write serve as a self reminder; things I have tried personally. In one of the recent encounters where a GUI tool wasn’t was possibility I was extra cautious while trying to roll back a production code that I had not committed to ensure no functionality gets broken.
This blog serves as a step-by-step reference guide for rolling back changes on branches that are already pushed to a remote.
—
The Golden Rule
If the branch is already pushed – use
– Saurabhgit revert. Nevergit reset --hard.
git revert adds a new commit that undoes your changes. History is preserved, no force push is needed, and collaborators are not affected.
git reset --hard + git push --force rewrites history. It is dangerous on shared branches and should only ever be used on branches that are 100% private and local.
—
Quick Reference Card
# 1. See recent commits
git log --oneline -15
# 2. Stage the revert (do NOT commit yet)
git revert --no-commit HEAD~N..HEAD # replace N with how many commits back
# 3. Inspect what will be undone
git diff --staged --stat # summary (file names + line counts)
git diff --staged # full line-by-line diff
# 4. Gold-standard validation (output should be empty)
git diff <target-hash> # compare staged result to intended target state
# 5a. Everything looks good → commit
git revert --continue
# 5b. Something is wrong → bail out completely
git revert --abort
# 6. Push (no force needed)
git push—
Step-by-Step Walkthrough
Step 1 — Know where you are
git log --oneline -15
git status
git branch -vvgit log --oneline -15 shows recent commits in compact form. Note down the hashes you want to undo.
git status confirms the working tree is clean before you start.
git branch -vv shows whether your branch is tracking a remote and whether it is ahead or behind. This tells you if the branch has already been pushed.
Example output:
a1b2c3d Added a broken feature ← HEAD (latest, bad)
d4e5f6g Updated configuration for new module ← HEAD~1 (also bad)
h7i8j9k Fixed unrelated bug ← HEAD~2 (this is where we want to land)
k0l1m2n Initial setup—
Step 2 — Understand what each commit changed
Before reverting anything, read the commits. Never revert blindly.
# Summary of files changed in a specific commit
git show --stat <hash>
# Full diff of a specific commit
git show <hash>
# Full diff of a specific commit, scoped to certain files only
git show <hash> -- path/to/file.py path/to/other.sh
# Combined diff across a range of commits
git diff <oldest-hash>..<newest-hash>—
Step 3 — Stage the revert without committing
This is the key safety move. The --no-commit flag applies the revert to the staging area but does not create a commit. You get a chance to inspect and abort before anything is permanent.
git revert --no-commit HEAD~N..HEADUnderstanding the range HEAD~N..HEAD:
The .. notation means the last N commits.
| You want to revert | Use this range |
|---|---|
| Last 1 commit | HEAD~1..HEAD |
| Last 2 commits | HEAD~2..HEAD |
| Last 3 commits | HEAD~3..HEAD |
| A specific commit | git revert --no-commit <hash> |
Common mistake:
HEAD~1..HEADonly covers the very last commit – not two commits. UseHEAD~2..HEADwhen you mean two commits back.
Git reverts commits in newest-first order automatically, which is the correct way to unwind a stack of changes.
—
Step 4 — Validate before committing
This is the most important part of the process. Never skip it.
# Quick check: which files are staged?
git status
# Summary: file names and changed line counts
git diff --staged --stat
# Full diff: read every line that will be undone
git diff --stagedThe gold-standard check — compare the staged result directly against the commit you are targeting:
git diff <hash-of-the-commit-you-want-to-land-on>If this command produces empty output, the staged state is byte-for-byte identical to that commit. The revert is perfect.
—
Step 5a — Commit when satisfied
git revert --continueGit opens your editor with a pre-filled commit message. You can edit it or accept the default. Save and close to finalize the commit.
—
Step 5b — Abort if something looks wrong
git revert --abortThis cancels everything and returns the repo to a clean state. No changes are made. Use this freely; it is completely safe.
—
Step 6 — Push
git pushBecause git revert preserves history, this is a plain push with no flags needed. The remote will accept it cleanly.
—
Why Not git reset?
Before revert: A → B → C → D (D is bad, you want to go back)
git revert: A → B → C → D → D' (D' undoes D, history intact)
git reset --hard: A → B → C (D is erased, history rewritten)| Description | git revert | git reset --hard + force push |
|---|---|---|
| Rewrites history | No | Yes |
| Safe on pushed branches | Yes | No |
Needs --force push | No | Yes |
| Undoable | Yes (revert the revert) | Very difficult |
| Affects collaborators | No | Yes — breaks their local branches |
The only situation where git reset --hard is acceptable is on a branch that has never been pushed and that only you are using.
—
Cheat Sheet: Diagnosing the Range
If you are unsure what a range covers, run this before reverting:
# List commits that would be reverted (dry run)
git log --oneline HEAD~N..HEADThe output shows exactly which commits will be undone. Confirm this matches your intention before proceeding.
—
Full Example
# 1. Check state
git log --oneline -5
# a1b2c3d Added a broken feature ← HEAD
# d4e5f6g Updated configuration for new module ← HEAD~1
# h7i8j9k Fixed unrelated bug ← HEAD~2 (target)
git status
# On branch my-feature-branch — nothing to commit, working tree clean
git branch -vv
# * my-feature-branch a1b2c3d [origin/my-feature-branch] ...
# 2. Verify what the commits changed
git show --stat a1b2c3d
git show --stat d4e5f6g
# 3. Stage the revert of the last 2 commits
git revert --no-commit HEAD~2..HEAD
# 4. Validate
git diff --staged --stat
git diff --staged
git diff h7i8j9k # empty output = perfect
# 5. Commit
git revert --continue
# 6. Push
git push—
Remembering It All
Think of the process as: Look → Understand → Stage → Validate → Commit → Push
git log → Look at the history
git show → Understand what each commit did
git revert --no-commit → Stage the undo (don't commit yet)
git diff --staged → Validate the staged result
git diff <target> → Gold-standard: confirm empty output
git revert --continue → Commit
git push → Push (no force needed)—
A practical guide to safe, history-preserving git rollbacks.
