Chapter 2.5 โ€” Undo Old Commits โ€” revert vs resetโ˜• 18 min read

Undo Old Commits โ€” revert vs reset

Shared branch pe revert karo, local branch pe reset. Yeh golden rule yaad rakhna โ€” team ka history mat todo!

01git revert โ€” The Safe Undo

git revert is the safe way to undo a commit. It creates a NEW commit that applies the inverse of the original changes โ€” like adding a negative to cancel out a positive.

The original commit stays in history, completely untouched. Nothing is deleted, nothing is rewritten. The revert commit simply says "undo these specific changes."

This is why revert is the only safe way to undo commits on shared/pushed branches: your teammates can see what was added and what was reverted. No force push, no rewritten history, no confusion.

Common revert commands:

  • git revert HEAD โ€” revert the last commit
  • git revert <hash> โ€” revert a specific older commit
  • git revert -n <hash> โ€” revert but don't auto-commit (stage the reversal, let you review first)

The revert commit message is auto-generated: Revert "original message". You can edit it before saving.

# Revert the last commit
git revert HEAD
# Opens editor with: Revert "feat: add login"
# Save to create the revert commit.

# Revert a specific commit
git revert abc1234

# Revert without committing (review first)
git revert -n abc1234
git status   # changes are staged but not committed
git commit -m "revert: remove broken feature"

# Revert multiple commits
git revert abc1234 def5678

# Revert a range (exclusive start, inclusive end)
git revert HEAD~3..HEAD
git revert does NOT delete history. It adds a new commit that applies the inverse of the original changes. Think of it as +5 then -5 = 0. The +5 commit is still in the log, but the net effect is zero. This is why revert is the only safe way to undo commits on shared branches.
02git reset โ€” The Dangerous Time Machine

git reset moves the branch pointer backward, as if certain commits never happened. It is a time machine โ€” but a dangerous one.

Unlike revert, reset rewrites history. The undone commits disappear from git log. If you already pushed those commits, resetting and force-pushing will destroy your teammates' work.

Three modes of reset, each progressively more destructive:

  • git reset --soft HEAD~1 โ€” moves branch pointer, keeps changes staged. Like "un-commit".
  • git reset --mixed HEAD~1 โ€” moves branch pointer, keeps changes in working directory unstaged. Like "un-commit + un-stage". This is the default.
  • git reset --hard HEAD~1 โ€” moves branch pointer, DELETES changes completely. Like "un-commit + throw away work".

Never use reset on shared/pushed branches. It requires force push and destroys team history. Reset is for local, unpushed commits only.

# --soft: Undo commit, keep changes staged
git reset --soft HEAD~1
git status  # Changes are staged (green)

# --mixed: Undo commit, keep changes unstaged (default)
git reset --mixed HEAD~1
# OR just: git reset HEAD~1
git status  # Changes are unstaged (red)

# --hard: Undo commit, DELETE ALL CHANGES
git reset --hard HEAD~1
git status  # "nothing to commit, working tree clean"
# Your changes are GONE (unless saved in reflog)

# Reset multiple commits
git reset --soft HEAD~3  # undo last 3 commits
๐Ÿ’ก Pro Tip: After any reset, the "undone" commits still exist in Git's reflog for 90 days. If you accidentally reset --hard, you can recover with git reflog to find the lost commit hash, then git reset --hard <hash> to get it back. But don't rely on this โ€” always double-check before --hard.
033 Modes of Reset: soft vs mixed vs hard

Think of Git having 3 areas: Repository (commits), Staging Area (index), Working Directory (your files on disk).

Each reset mode affects a different combination of these areas:

  • --soft: Moves Repository pointer. Staging and Working stay the same. Your work is preserved and ready to recommit.
  • --mixed: Moves Repository pointer + resets Staging. Working stays the same. Your files are safe but need to be re-staged.
  • --hard: Moves Repository pointer + resets Staging + resets Working. Everything gone.

Easy memory trick: --soft = safest (work preserved), --hard = harshest (work destroyed).

# Start with a commit that added "Hello World" to app.js
echo "Hello World" > app.js
git add app.js
git commit -m "add greeting"

# --soft: Commit undone, "Hello World" is still staged
git reset --soft HEAD~1
git status
# new file: app.js (in staging - green)
# Ready to recommit immediately.

# --mixed: Commit undone, "Hello World" is unstaged
git reset --mixed HEAD~1
git status
# Untracked files: app.js (in working dir - red)
# Need to git add before committing.

# --hard: Commit undone, app.js is DELETED
git reset --hard HEAD~1
git status
# nothing to commit, working tree clean
# app.js and its content are GONE from disk.
Think of reset modes as levels of destruction: --soft just removes the commit label but keeps everything else. --mixed removes the commit AND unstages changes. --hard removes the commit AND deletes your work. The further you go, the harder it is to recover. When in doubt, start with --soft.
04Golden Rule โ€” Revert for Public, Reset for Private

The golden rule of undoing commits: revert for public, reset for private.

Use git revert when:

  • The commit is on a shared/pushed branch
  • You want a record of the undo in history
  • You are working with a team

Use git reset when:

  • The commit is local and unpushed
  • You want to clean up your own mess before anyone sees it
  • You want to reorganize commits before sharing

If in doubt, use revert. It is always safe. Reset can always be replaced with revert โ€” the reverse is not true once you have pushed.

Never reset a commit that someone else might have pulled.

# SCENARIO 1: Local commit, not pushed -> RESET
git commit -m "WIP: broken experiment"
# I want to undo this and try again
git reset --soft HEAD~1
# Safe: only I have this commit locally.

# SCENARIO 2: Pushed commit, shared branch -> REVERT
git push origin main
# This commit broke production!
git revert HEAD
git push origin main
# Safe: team can see the fix in history.

# SCENARIO 3: Local feature branch, cleaning up -> RESET
git rebase -i HEAD~5
# Squashing WIP commits before PR
# Reset or rebase is fine here since branch is not shared yet.

# SCENARIO 4: Revert a merge commit
git revert -m 1 <merge-hash>
# -m 1 means "keep the first parent's history"
# Required for reverting merge commits.
๐Ÿ’ก Real-world rule: If the commit is on main, develop, or any branch that others pull from โ€” always revert. If it is on your personal feature branch that nobody else uses โ€” reset is fine. When in doubt, revert.
05Reverting Merge Commits & Revert Revert Pattern

Reverting a merge commit requires the -m parent-number flag because merge commits have two parents โ€” Git needs to know which side of the fork to keep.

git revert -m 1 <merge-hash> โ€” revert a merge, keeping main's history (parent 1 is usually the branch you merged into).

Reverting a revert is a common pattern in release management. If you revert a feature for a release, then want to bring it back in the next release, you revert the revert commit.

git revert <revert-hash> โ€” this "re-reverts", effectively bringing the original changes back.

If a revert conflicts, it means the commit cannot be cleanly reversed. Resolve the conflict, then continue the revert.

# Revert a merge commit
git log --oneline
# abc1234 Merge pull request #42
# Must specify parent (-m flag)
git revert -m 1 abc1234
# -m 1 = keep main branch history, undo feature branch

# Reverting a revert (bringing changes back)
git log --oneline
# def5678 Revert "feat: add dashboard"
# abc1234 feat: add dashboard
git revert def5678
# This "re-reverts", effectively bringing dashboard back!

# Revert with conflict
git revert xyz1234
# CONFLICT (content): Merge conflict in app.js
# Resolve conflict, then:
git add app.js
git revert --continue
Why revert a revert instead of just re-merging? If you merged a feature branch, then reverted the merge, re-merging the same branch won't work โ€” Git thinks those commits are already included (they were, then reverted). The only way to bring those changes back is to revert the revert commit. This is a Git gotcha that catches many teams off guard.

Lo kar liya โ€” Key Points:

  • โœ… git revert <hash> creates a new "anti-commit" that undoes changes โ€” safe for shared/pushed branches
  • โœ… git reset moves the branch pointer backward, erasing commits from history โ€” only for local/unpushed branches
  • โœ… git reset --soft keeps changes staged, --mixed keeps them unstaged, --hard deletes them entirely
  • โœ… Golden rule: revert for public/shared branches, reset for private/local branches
  • โœ… Reverting a merge commit requires -m parent-number flag to specify which parent to keep
  • โœ… Reverting a revert brings the original changes back โ€” common in release management
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase