
Post: Git Rollback Commands: Master Revert, Reset, and Reflog
Git gives developers three essential rollback commands: git revert creates a new undo commit that is safe for shared branches, git reset rewrites local history before you push, and git reflog recovers commits you thought were gone after an accidental hard reset. Know when to use each and no mistake is permanent.
Why Git Rollback Is a Core Developer Skill
Every developer pushes broken code at some point – the difference between a five-minute fix and a two-hour incident is knowing which rollback command fits the situation.
Git stores your repository as a chain of snapshots linked by SHA-1 hashes. When you undo something, you’re either adding a new commit that cancels a prior one, or moving the branch pointer to a different position in that chain. Git rarely destroys data outright – it makes data unreachable. That distinction matters because unreachable data is recoverable data, and understanding it is what separates developers who panic from developers who have a plan.
Git Revert: The Safe Undo for Shared Branches
git revert creates a new commit that inverts the changes from a previous commit, leaving both commits in the history.
That makes it the right call whenever you’re working on a shared or public branch. Teammates pulling from that branch never see a history rewrite – they just see a new commit. If commit A introduced a bug, git revert A produces commit B that removes A’s changes while keeping both in the log. The audit trail stays clean and collaboration stays conflict-free.
When to use it: Any time a broken commit has already been pushed to a shared branch. This is the correct path in a collaborative codebase – it respects the history everyone else is working from.
Basic usage:
git revert HEAD
Git opens your default editor to confirm the revert commit message. Save and exit, and the undo is committed to the branch automatically. You can also pass any commit hash, not just HEAD, to revert further back in history.
Git Reset: Rewrite Local History Before You Push
git reset moves the HEAD pointer to a prior commit and erases everything that came after it from your branch’s visible history.
Unlike revert, reset rewrites history – which is exactly why it belongs in your local workflow before you push, not on branches teammates are working from. Three modes control how aggressively it cleans up:
--soft: HEAD moves back but your staging area and working directory stay as-is. All changes from the discarded commits are staged and ready for a new commit.--mixed(default): HEAD moves back and the staging area resets, but your working directory is untouched. Changes from discarded commits show as unstaged files.--hard: HEAD moves back, staging resets, and your working directory is rewritten to match the target commit. Changes from discarded commits are gone from disk. No undo except reflog.
When to use it: Cleaning up a messy local commit sequence before pushing, squashing experiments that didn’t pan out, or completely abandoning a line of work on a branch only you’re using.
Undo the last two local commits, keep changes unstaged:
git reset HEAD~2
Discard everything back to a specific commit hash:
git reset --hard <commit_hash>
Git Reflog: Recover Commits After a Hard Reset
git reflog records every time HEAD has moved – commits, merges, resets, checkouts – in a local journal that stays on your machine.
That journal is the safety net for hard resets. Even after git reset --hard moves your branch pointer and makes commits unreachable by name, those commit objects sit in Git’s internal database until garbage collection runs. Reflog gives you their hashes so you can jump back to any prior state.
View the reflog:
git reflog
Each line shows a hash, the operation that moved HEAD, and a short description. Find the entry that predates your reset, then jump back to it:
git reset --hard <reflog_entry_hash>
Reflog is strictly local – it does not push to remotes. If you’re working from a fresh clone, reflog won’t have history from another machine. That’s why regular pushes to a remote are the real backup strategy, and reflog is the emergency exit for local mistakes only.
Expert Take
The most common and damaging mistake developers make with these commands is running git reset on a branch that teammates are pulling from. Reset moves a pointer – from their perspective, history has disappeared and reconciliation becomes a multi-person problem fast. Revert is the rule on shared branches. Reset is for local work only, full stop. Reflog exists for the moment someone forgets that rule.
Cherry-Pick: Apply One Commit Without a Full Merge
git cherry-pick applies the changes from a specific commit onto your current branch without pulling in the entire source branch.
It’s not a rollback command, but it belongs in this toolkit. When you need to bring a bug fix from a feature branch into main without merging every surrounding commit, cherry-pick handles it cleanly. One commit, applied precisely where you need it.
git cherry-pick <commit_hash>
Cherry-pick creates a new commit on your current branch with the same changes – same diff, new hash, new position in history. Conflicts are flagged the same way a merge conflict is, so the resolution process is familiar.
Choosing the Right Command for the Situation
The decision tree is straightforward: pushed to a shared branch, use revert; local and unpushed, use reset; reset too aggressively, use reflog to recover.
Keeping those three boundaries clear is what prevents a simple undo from becoming a team-wide incident. Most Git disasters trace back to one cause – applying a local-only tool to a shared branch, not any inherent complexity in the commands themselves. Get the boundaries right and all three commands are safe, precise, and fast.
For more on protecting and restoring version-controlled data in business systems, read 13 Essential Strategies for Robust CRM Data Protection and Business Continuity in HR Recruiting.

