Back to Git: Branching, Merge, Rebase
Q2Question 2 of 6

`git reset` vs `git revert`, and what `git reflog` is

Key Concepts
  • git reset moves the branch pointer backward, dropping commits from the branch -- this rewrites history and is safe only on local, unshared commits.
  • git reset has three modes: --soft keeps changes staged, --mixed keeps them unstaged, --hard discards everything (dangerous).
  • git revert creates a new commit that applies the inverse of a target commit, leaving all history intact -- safe for shared branches.
  • Use reset for local undoing, revert for public undoing -- revert preserves the audit trail a bank requires.
  • git reflog records every position HEAD has pointed to, so even after a hard reset, lost commits can be recovered.
  • Reflog is local and has an expiry -- unreferenced commits are eventually garbage-collected, so recovery is for recent mistakes.
  • Reverting a merge commit requires specifying which parent to keep with the -m flag.

Definition

reset rewrites history by moving the branch pointer (local only), revert safely cancels a commit with a new inverse commit (shared-safe), and reflog is your safety net to recover lost commits.
  • git reset -- moves the current branch pointer to an earlier commit, effectively rewriting history; its three modes control what happens to staged and working changes.
  • --soft -- moves pointer but leaves changes staged, ready to recommit.
  • --mixed -- moves pointer and unstages changes but keeps them in the working directory (default).
  • --hard -- moves pointer and discards all changes in staging and working directory (dangerous).
  • git revert -- creates a new commit that applies the inverse of a target commit, canceling its effect without rewriting history.
  • git reflog -- a local log recording every position HEAD has pointed to, used to recover commits lost after a bad reset or rebase.

Imagine correcting a mistaken entry in National Bank of India's ledger. git reset is like tearing the last page out -- fine if only you have seen it, but disastrous if other branches already copied it. git revert is the proper banking way: write a new correcting entry that cancels the mistake, so the full audit trail stays intact. git reflog is the bank's CCTV log that records every move, so even if you tore out a page, you can look at the footage and restore it.

Understanding the Concepts

How does git reset work?

git reset moves the tip of your current branch to point at a different commit, usually an earlier one. The commits after the new position are no longer part of the branch history -- this is a history rewrite.

BASH
# Current history
git log --oneline -4
TEXT
abc1234 feat: add prepayment penalty (WRONG -- should not have committed)
def5678 feat: add EMI calculation
ghi9012 fix: transfer rounding
jkl3456 initial payment service
BASH
# Soft reset: move pointer back, keep changes staged
git reset --soft HEAD~1
git status
TEXT
Changes to be committed:
  new file: src/main/java/com/bank/loans/PrepaymentPenalty.java
# The commit is gone, but the code is still staged -- ready to recommit differently
BASH
# Mixed reset (default): move pointer, unstage changes
git reset HEAD~1
git status
TEXT
Changes not staged for commit:
  new file: src/main/java/com/bank/loans/PrepaymentPenalty.java
# Changes are in working directory, unstaged
BASH
# Hard reset: move pointer and DISCARD everything
git reset --hard HEAD~1
git status
TEXT
On branch feature/emi-calculation
nothing to commit, working tree clean
# The file is GONE -- uncommitted work is lost

Why is reset safe only on local commits?

Reset rewrites history. If you reset commits that were already pushed and teammates pulled them, your local branch diverges from theirs. Force-pushing then overwrites commits others depend on.

BASH
# WRONG -- reset a pushed commit and force-push
git reset --hard HEAD~1
git push --force origin feature/emi-calculation
# Priya's copy still has the old commit -- her branch is now broken

# CORRECT -- reset only local, unpushed commits
git reset --soft HEAD~1
# Fix the commit message or content, then recommit
git commit -m "feat: add EMI calculation with correct rounding"

How does git revert work?

git revert computes the inverse of a commit and records it as a new commit. If the original commit added a line, the revert removes it. The original commit stays in history, and the new commit cancels its effect. Nothing is rewritten.

BASH
# Revert a bad commit that was already pushed
git log --oneline -3
TEXT
abc1234 feat: add prepayment penalty (deployed, found bug)
def5678 feat: add EMI calculation
ghi9012 fix: transfer rounding
BASH
git revert abc1234
TEXT
[main xyz789] Revert "feat: add prepayment penalty"
 1 file changed, 0 insertions(+), 25 deletions(-)
BASH
git log --oneline -4
TEXT
xyz789 Revert "feat: add prepayment penalty"
abc1234 feat: add prepayment penalty
def5678 feat: add EMI calculation
ghi9012 fix: transfer rounding
# Both the mistake and correction are visible -- audit trail intact

When do you use reset vs revert?

The decision rule is simple. If the commit is local and unshared, reset is fine and often cleaner. If the commit is already pushed and others may have it, use revert so you never rewrite shared history.

| Scenario | Use reset | Use revert |
|---|---|---|
| Local commit, not yet pushed | reset --soft or --mixed | -- |
| Already pushed, teammates pulled | -- | revert |
| Merge commit already public | -- | revert -m 1 |
| Wrong commit message (local) | reset --soft, recommit | -- |

JAVA
package com.bank.loans;

import java.math.BigDecimal;

/**
 * This class was added in abc1234 and reverted in xyz789
 * because the penalty calculation had a rounding bug.
 * The revert keeps both commits visible for auditors.
 */
public class PrepaymentPenalty {

    public BigDecimal calculate(BigDecimal outstanding) {
        // Bug: should use RoundingMode.HALF_UP
        return outstanding.multiply(new BigDecimal("0.02"));
    }
}

How does git reflog work?

Every time HEAD moves -- commit, checkout, reset, rebase, merge -- Git records the previous position in the reflog. Even after a hard reset, the dropped commits are not deleted immediately. You find the entry before the mistake and recover.

BASH
git reflog
TEXT
abc1234 HEAD@{0}: reset: moving to HEAD~1
def5678 HEAD@{1}: commit: feat: add prepayment penalty
ghi9012 HEAD@{2}: commit: feat: add EMI calculation
jkl3456 HEAD@{3}: checkout: moving from main to feature/emi
BASH
# Recover the commit lost by reset
git reset --hard HEAD@{1}
# OR create a branch at the lost commit
git branch recovered-prepayment HEAD@{1}
TEXT
HEAD is now at def5678 feat: add prepayment penalty
# The "lost" commit is back

How do you revert a merge commit?

Reverting a merge commit requires the -m flag to specify which parent to keep. Parent 1 is the branch you were on when you merged, parent 2 is the branch you merged in.

BASH
# Revert a merge commit, keeping parent 1 (main)
git revert -m 1 abc1234
TEXT
[main xyz789] Revert "Merge branch 'feature/broken-penalty'"
 3 files changed, 0 insertions(+), 50 deletions(-)

What are common mistakes?

The most common mistakes are using reset --hard on pushed commits, not knowing that reflog can recover from a bad reset, using revert when reset would be cleaner for a local mistake, and force-pushing after a reset without --force-with-lease.

BASH
# WRONG -- hard reset a pushed commit
git reset --hard HEAD~1
git push --force origin main  # destroys teammate's work

# CORRECT -- revert the pushed commit
git revert HEAD
git push origin main  # normal push, no force needed

What should a senior engineer know?

A senior engineer knows that reflog is local with an expiry, so it recovers recent mistakes but not ancient ones. They know that revert preserves the full audit trail a bank requires. They know that for a mistaken merge already pushed, revert -m 1 is the safe tool. They use reset --soft to reshape local commits before sharing, and they never hard-reset shared history.

Visual Overview

DIAGRAM
  git reset (three modes)
  ───────────────────────

  Before: A ── B ── C (HEAD)

  --soft:  A ── B (HEAD)     C's changes: STAGED
  --mixed: A ── B (HEAD)     C's changes: UNSTAGED (in working dir)
  --hard:  A ── B (HEAD)     C's changes: GONE

  git revert (new inverse commit)
  ───────────────────────────────

  Before: A ── B ── C (HEAD)
  After:  A ── B ── C ── C' (HEAD)
  C' = inverse of C, history intact

  Decision:
  ┌─────────────────┐     ┌─────────────────┐
  │ Commit is LOCAL   │     │ Commit is PUSHED  │
  │ (not yet pushed)  │     │ (others have it)  │
  │                   │     │                   │
  │ Use: git reset    │     │ Use: git revert   │
  │ (rewrite is safe) │     │ (no rewrite)      │
  └─────────────────┘     └─────────────────┘

  Reflog (safety net):
  ┌───────────────────────────────────────────┐
  │ HEAD@{0}: reset: moving to HEAD~1          │
  │ HEAD@{1}: commit: add prepayment penalty   │ ◀── recover here
  │ HEAD@{2}: commit: add EMI calculation      │
  │ HEAD@{3}: checkout: main to feature/emi    │
  └───────────────────────────────────────────┘

Key Takeaway

git reset and git revert both undo changes but work in opposite ways. Reset moves the branch pointer backward, dropping commits from the branch, which is a history rewrite safe only on local, unshared commits. It has three modes: soft keeps changes staged, mixed keeps them unstaged, and hard discards them entirely. Revert creates a new commit that applies the inverse of the target, leaving all history intact, which makes it safe for shared branches.

The decision rule is simple: if the commit is local and unshared, reset is fine and often cleaner. If the commit is already pushed, use revert so you never rewrite shared history. For a bank, revert has the added benefit of preserving the full audit trail -- auditors can see both the mistake and its correction.

git reflog is the safety net. Every time HEAD moves, Git records the position, so even after a hard reset that appears to destroy commits, those commits are only unreferenced and the reflog remembers their hashes. You recover by resetting to the pre-mistake entry.

Remember one sentence: use reset for local undoing and revert for public undoing, and if you make a mistake, reflog is your safety net to recover lost commits.

---

Share
Use ← → arrow keys to navigate