Skip to content
ExponaBLOG
GIT & GITHUB FOR PROFESSIONAL DEVELOPERS · DAY 017 / 100

git revert vs git reset: real-world lessons and examples

Undo safely on shared branches.

Expona Admin7 min read

The moment of truth: when you commit the wrong code

It's 2 PM on a Tuesday. Your team is working on a new payment feature, and someone just pushed a commit that breaks the CI/CD pipeline. Everyone's waiting. You need to undo it—but do you use git revert or git reset? The answer matters more than you'd think, and choosing wrong can create merge conflicts or rewrite history that your teammates depend on. Understanding git revert vs git reset: real-world lessons and examples is one of the most practical skills you'll use in a professional codebase.

Both commands undo changes, but they work in fundamentally different ways. One is safe for shared branches; the other can break your team's workflow. Let's walk through when and how to use each.

Reset moves the branch pointer

git reset is a powerful command that actually moves the branch pointer backward in the commit history. It doesn't create a new commit—it rewrites history. When you run git reset, you're telling Git to pretend certain commits never happened on that branch.

There are three modes:

  • --soft: moves the pointer but keeps your changes staged
  • --mixed (default): moves the pointer and unstages your changes
  • --hard: moves the pointer and discards your changes entirely

Here's a real scenario. You're on your local feature/checkout-form branch. You've made three commits, but the second one added a debug log statement you forgot to remove:

bash
$ git log --oneline
a3f2b1c Add payment validation (contains debug log)
b2e1a0d Add form fields
c1d0a9f Initial checkout setup

You want to undo just that one commit but keep the validation logic. You'd use:

bash
$ git reset --soft HEAD~1

Now your branch pointer moves back one commit, but your changes are still staged. You can edit them, remove the debug log, and commit cleanly. This is safe because you're working alone on this branch.

The danger comes when you reset on a shared branch. If you've already pushed those commits to main and others have pulled them, resetting will create a diverged history. When your teammates try to push, they'll get rejected or forced to resolve conflicts that shouldn't exist. Worse, they might force-push their own reset, overwriting your team's work.

Revert creates a new commit that undoes changes

git revert takes a different approach. Instead of moving the pointer, it creates a brand-new commit that applies the inverse of the changes you want to undo. The old commits stay in history—they're just negated by the new one.

Let's use the same scenario, but now imagine that debug log commit is already on the shared main branch and other developers have pulled it:

bash
$ git log --oneline
a3f2b1c Add payment validation (contains debug log)
b2e1a0d Add form fields
c1d0a9f Initial checkout setup

You run:

bash
$ git revert a3f2b1c

Git creates a new commit that reverses the changes from a3f2b1c. Your log now looks like:

bash
$ git log --oneline
d4f3c2e Revert "Add payment validation (contains debug log)"
a3f2b1c Add payment validation (contains debug log)
b2e1a0d Add form fields
c1d0a9f Initial checkout setup

The original commit is still there. You can see what happened and why. When your teammates pull, they get a clean, linear history. No conflicts. No surprises. No force-pushing required.

The trade-off is that your history includes both the bad commit and the revert. In large codebases, this makes the log easier to audit but slightly noisier. Most teams consider that a fair price for safety on shared branches.

Use revert on shared branches

The golden rule: if a commit has been pushed to a shared branch—main, develop, or any branch that multiple developers work on—use git revert.

Let's say your team discovered that a commit in main introduced a memory leak in the API response handler. It's been there for two days. Multiple people have based their work on it. Here's how you handle it:

bash
$ git checkout main
$ git pull origin main
$ git log --oneline | head -5
5e4d3c2 Fix typo in docs
4d3c2b1 Add memory leak to API handler (this is the bad one)
3c2b1a0 Refactor cache layer
2b1a0f9 Add new endpoint
1a0f8e8 Initial setup

$ git revert 4d3c2b1

This opens your editor (usually Vim or your configured default) with a generated commit message:

bash
Revert "Add memory leak to API handler"

This reverts commit 4d3c2b1.

You can edit it to explain why:

bash
Revert "Add memory leak to API handler"

This reverts commit 4d3c2b1.

Reason: Memory leak identified in response handler. 
Reverting until root cause is fixed.

You save and exit. The revert commit is created. You push it:

bash
$ git push origin main

Your team sees the revert in their feeds. They can see why you did it. They pull and continue working. No broken builds for them. No conflicts. The codebase is stable again.

If you had used git reset --hard instead, their next pull would have failed or created a merge nightmare. Worse, they might not even realize the history changed.

Use reset on local work

git reset is your best friend when you're working locally and haven't shared anything yet. It's fast, clean, and doesn't clutter the shared history.

Common scenarios:

  • You made three commits on a feature branch, realized you went down the wrong path, and want to start over.
  • You committed work-in-progress code and want to unstage it before pushing.
  • You want to squash multiple local commits into one coherent commit before pushing.

Here's a practical example. You're building a new dashboard and created this commit history:

bash
$ git log --oneline
f5e4d3c Add chart rendering
e4d3c2b Add data fetching
d3c2b1a WIP: debugging chart margins
c2b1a0f Add initial dashboard layout

Commits three commits ago, you branched from main. Nothing's been pushed. You realize the data-fetching approach isn't right. You want to undo the last two commits but keep the layout:

bash
$ git reset --soft HEAD~2

Now you're back at d3c2b1a, but all the changes from the last two commits are staged and ready to edit:

bash
$ git status
On branch feature/dashboard
Changes to be committed:
  modified:   src/components/Dashboard.jsx
  modified:   src/api/dashboardApi.js

You can unstage, edit, and recommit properly:

bash
$ git reset HEAD src/api/dashboardApi.js
$ # Edit the file
$ git add src/api/dashboardApi.js
$ git commit -m "Fetch dashboard data with improved error handling"

Clean history, no wasted commits, no shared damage. This is what git reset is for.

Common mistakes

Mistake 1: Using git reset on a shared branch and force-pushing. This rewrites history for everyone. Your teammates' branches will diverge, and merges become painful. If you've already pushed, use git revert instead.

Mistake 2: Using git revert on local commits and polluting your history. If you haven't pushed yet, git reset is cleaner. Revert creates unnecessary commits that clutter the log. Save revert for shared branches.

Mistake 3: Not checking what you're resetting. git reset --hard is destructive. Before running it, verify with git log or git diff exactly which commits you're removing. Once the commits are gone locally, they're hard to recover.

Mistake 4: Reverting the wrong commit. Make sure you have the commit hash right. If you revert the wrong one, you've just introduced a new commit that undoes good code. You can revert the revert, but it's an extra step.

Mistake 5: Confusing git revert with git reset in a team setting and assuming one is "safer". Neither is safer in isolation—context determines which to use. Revert is safer on shared branches. Reset is safer on local work. Use the wrong one in the wrong place, and you cause problems.

Key takeaways

  • git reset moves the branch pointer and rewrites history. It's clean and fast for local work but dangerous on shared branches.
  • git revert creates a new commit that undoes changes. It preserves history and is safe for shared branches.
  • If a commit is already on a shared branch that others have pulled, use git revert.
  • If a commit is only on your local branch and hasn't been pushed, use git reset to keep history clean.
  • Always check your commit hash and branch status before running either command, especially with --hard flags.
  • Communicate with your team when you need to undo commits on shared branches. Leave a clear commit message explaining why.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles