Git Reset vs Revert vs Restore: Differences, Use Cases & Examples (2026 Guide)

By Kedar Salunkhe | Last Updated: March 2026

Let’s be honest for a second.

If you’ve been using Git for more than a few months, you’ve probably had one of those moments. You ran a command — maybe git reset, maybe something else — and then immediately thought: “Wait. Did I just lose my work?”

That stomach-drop feeling. The frantic git log to see if your commits are still there. The relief when everything is fine. The mental note to “look this up properly someday.”

Most developers use git reset, git revert, and git restore as if they’re interchangeable panic buttons. Hit one when something goes wrong and hope for the best. That approach works right up until the moment it doesn’t — and when it fails, it fails in ways that affect your entire team.

Here’s what makes this genuinely confusing: all three commands are about undoing things. All three involve the word “git.” All three are suggested in Stack Overflow answers for seemingly similar problems. But they operate on completely different parts of your repository, affect different people, and carry very different risk profiles.

This guide draws a clean line between all three. By the end, you won’t just know the commands — you’ll know exactly which one to reach for, why, and what to expect when you run it. No more stomach drops.


Git Reset vs Revert vs Restore: Differences, Use Cases & Examples (2026 Guide)


The Mental Model You Need First

Before diving into commands, spend two minutes with this mental model — it makes everything else click immediately.

Your Git repository has three distinct “places” where your work lives at any given time:

The working directory — where you actually edit files. This is your raw, unsaved-to-Git state. Changes here are just changes on your filesystem. Git knows about them but isn’t tracking them yet.

The staging area (also called the index) — where you put changes when you run git add. This is the “prepared for commit” zone. Changes here are tracked and ready to be committed.

The commit history — the permanent (or semi-permanent) record of all your commits. Each commit is a snapshot of your staged files at the time you ran git commit.

Now here’s the key insight that separates reset, revert, and restore:

git restore — operates on the working directory and staging area. It does not touch commit history.

git reset — operates on commit history AND optionally on the staging area and working directory. It moves branch pointers.

git revert — operates only on commit history. It adds a new commit rather than removing or modifying existing ones.

If you remember nothing else from this guide, remember this: restore touches files, reset touches commits (and optionally files), revert only adds commits.

Everything else follows from this.


What Is git restore? (And Why It’s the Safest of the Three)

What Is git restore? (And Why It's the Safest of the Three)

git restore was introduced in Git 2.23 (released in 2019) as a cleaner, more explicit alternative to using git checkout for file operations. Before 2.23, developers used git checkout — filename to discard changes in the working directory — a confusing overloading of a command that also switches branches.

git restore was created specifically for one job: restoring file content. That’s it. It doesn’t touch commits. It doesn’t move branches. It just puts file content back to a specific state.

What git restore Does

Discard changes in the working directory (restore a file to its last committed state):

git restore filename.js

Unstage a file (move it from staging area back to working directory without losing changes):

git restore --staged filename.js

Restore a file to the state it was in at a specific commit:

git restore --source=COMMIT-HASH filename.js

Restore multiple files at once:

git restore .

Restore everything to the last commit state (discards all uncommitted changes):

git restore --staged --worktree .

What git restore Does NOT Do

It does not delete commits. It does not move branch pointers. It does not affect other people’s repositories. It does not touch anything it isn’t explicitly told to touch.

This is why it’s the safest of the three commands. Its scope is limited by design.

Use Cases for git restore

You edited a file and decided you don’t want those changes:

git restore config.js

You accidentally staged a file with a sensitive change and want to unstage it without losing the content:

git restore –staged .env

You want to see what a specific file looked like in a previous commit without checking out the whole commit:

git restore –source=a1b2c3d old-feature.js

You staged twenty files and want to unstage one specific one:

git restore –staged accidental-file.js

Real Example

$ git status
On branch feature/dashboard
Changes to be committed:
(use "git restore --staged …" to unstage)
modified: dashboard.js
modified: debug-helper.js
Changes not staged for commit:
(use "git restore …" to discard changes in working directory)
modified: config.js

[Oh no — debug-helper.js should not be in this commit. And config.js changes were experimental and unwanted.]

$ git restore --staged debug-helper.js
[Unstaged debug-helper.js — changes still in working directory, just not staged]

$ git restore config.js
[Discarded working directory changes to config.js — reverted to last committed version]

$ git status
On branch feature/dashboard
Changes to be committed:
modified: dashboard.js
Changes not staged for commit:
modified: debug-helper.js

Clean — only dashboard.js is staged, debug-helper.js is unstaged, config.js is back to clean]

The One Thing to Be Careful About

git restore without –staged discards your working directory changes permanently. Unlike staging and committing, changes discarded with git restore cannot be recovered with git reflog. If you run git restore filename.js and the file had unsaved changes that were never staged or committed, those changes are gone.

Before using git restore to discard working directory changes, make sure you genuinely don’t need them. If in doubt, stage them first (git add filename.js) before discarding — that way they’re at least accessible through a commit history approach.


What Is git reset? (The Powerful, Context-Sensitive One)

What Is git reset? (The Powerful, Context-Sensitive One)

git reset is the most powerful and most misunderstood of the three commands. It moves the current branch pointer to a different commit — and depending on the flags you use, it also changes the state of your staging area and working directory.

Think of it this way: git reset says “Pretend the branch pointer was always here, not where it currently is.” Everything that was in commits after the new pointer position gets displaced — where those displaced changes end up depends on which flag you use.

The Three Modes of git reset

git reset has three modes, each defined by a flag. Understanding the difference between these three flags is the whole ballgame:

git reset –soft

Moves the branch pointer. That’s it. The staging area and working directory are unchanged.

Effect: Commits are removed from history. The changes that were in those commits are now in the staging area, as if you had just staged them but not yet committed.

git reset –soft HEAD~1

git reset –mixed (default)

Moves the branch pointer AND clears the staging area.

Effect: Commits are removed from history. The changes that were in those commits are now in the working directory as unstaged changes.

git reset HEAD~1
(identical to git reset –mixed HEAD~1)

git reset –hard

Moves the branch pointer AND clears the staging area AND resets the working directory.

Effect: Commits are removed from history. The changes that were in those commits are gone from your working directory too. This is the dangerous one.

git reset –hard HEAD~1

Visual Breakdown

Command | Commit history | Staging area | Working directory
git reset –soft | Changed | Unchanged | Unchanged
git reset –mixed | Changed | Cleared | Unchanged
git reset –hard | Changed | Cleared | Cleared (changes lost)

Use Cases for git reset

Undo the last commit but keep the changes staged (to fix the message or add something):

git reset –soft HEAD~1

Undo the last commit and unstage everything for a careful review:

git reset –mixed HEAD~1

Go back three commits and see all those changes as unstaged:

git reset HEAD~3

Discard everything since the last commit entirely (and mean it):

git reset –hard HEAD

Reset a specific file in the staging area to match the latest commit (alternative to git restore –staged):

git reset HEAD filename.js

Reset your branch to match exactly what’s on the remote (dangerous on shared branches):

git reset –hard origin/main

The Critical Safety Question

Before running git reset, answer this: has the commit I’m resetting already been pushed to a remote that other people use?

If no — reset freely. You’re rewriting local history that exists only on your machine.

If yes — stop. Do not use git reset on shared branches. Use git revert instead. Resetting a commit that others have already pulled will create a diverged history that causes painful merge conflicts for your entire team.

There is one exception: if you are the only person using that remote branch (your personal feature branch), a git reset followed by git push –force is acceptable. But it should be deliberate and done with the awareness of what you’re doing.

Real Example — The Wrong Branch Scenario

Happens to every developer eventually. You committed to main when you should have committed to a feature branch.

$ git log --oneline
a1b2c3d (HEAD -> main) Add experimental caching layer
e4f5g6h Stable release checkpoint

[This commit belongs on feature/caching, not main]

$ git reset --soft HEAD~1
[Commit removed, changes still staged]

$ git stash
Saved working directory and index state WIP on main: e4f5g6h Stable release checkpoint

$ git checkout -b feature/caching
Switched to a new branch 'feature/caching'

$ git stash pop
On branch feature/caching
Changes to be committed:
modified: cache-layer.js
new file: cache-config.js

$ git commit -m "Add experimental caching layer"
[feature/caching a2b3c4d] Add experimental caching layer

[Commit moved from main to the correct branch. main is clean.]

Real Example — Cleaning Up Before a Code Review

You made three quick “WIP” commits while figuring something out, and now you want to squash them into one clean commit before creating a pull request.

$ git log --oneline
c3d4e5f (HEAD -> feature/search) WIP: trying full text search
b2c3d4e WIP: refactoring search query
a1b2c3d WIP: started search feature
9i8j7k6 Last clean commit

$ git reset --soft HEAD~3
[Three commits removed. All changes now staged.]

$ git status
On branch feature/search
Changes to be committed:
modified: search.js
modified: search-index.js
new file: full-text-search.js

$ git commit -m "Implement full text search with indexing"
[feature/search d4e5f6g] Implement full text search with indexing

[Three messy WIP commits squashed into one clean commit. Ready for review.]

What Is git revert? (The Team-Friendly Undo)

What Is git revert? (The Team-Friendly Undo)

git revert is the command that gets the least appreciation and the most underuse. It’s the cautious, professional, grown-up way to undo a change — and it’s the only option that’s genuinely safe on shared branches.

Here’s what makes it different from reset: instead of going back in time and removing a commit, git revert creates a new commit that applies the inverse of a previous commit. The original commit stays in history. A new “revert” commit is added that undoes its effects. Net result: the code is back to where it was before the original commit, but the history shows both the original change and the explicit decision to undo it.

Why This Matters in a Team Context

Imagine you and two teammates are all working off main. Someone pushes a commit that breaks the build. You need to undo it immediately.

If you use git reset and force push, you rewrite history. Your teammates’ local repositories still have the original commit. The next time they push, they’ll have a history conflict. You’ve just turned a one-person problem into a three-person debugging session.

If you use git revert, you push a new commit to main that undoes the broken code. Your teammates pull it as a normal new commit. No conflicts. No force push. No disruption. The fix lands in seconds, and everyone moves on.

That’s why git revert exists. It’s not just a philosophical preference — it’s a practical tool for maintaining a coherent shared history.

The Command

Revert the most recent commit:

git revert HEAD

Revert a specific commit anywhere in history (use the hash from git log –oneline):

git revert a1b2c3d

Revert a range of commits (creates one revert commit per original commit):

git revert HEAD~3..HEAD

Revert without opening the editor for the commit message (uses the default “Revert ‘original message'” format):

git revert HEAD –no-edit

Stage the revert changes without committing immediately (useful if you want to review or modify before committing):

git revert HEAD –no-commit

Use Cases for git revert

Undo a commit that has already been pushed to main or develop:

git revert HEAD
git push origin main

Roll back a feature that introduced a bug, without rewriting history:

git revert a1b2c3d
git push origin main

Undo a merge commit (requires the -m flag to specify which parent to revert to):

git revert -m 1 MERGE-COMMIT-HASH

Create a clear audit trail showing that a change was explicitly undone (important in regulated or compliance-tracked environments):

git revert a1b2c3d --no-edit

Handling Conflicts in a Revert

If the commit you’re reverting touched files that were also changed by subsequent commits, Git may not be able to automatically create the inverse patch. It’ll tell you:

error: could not revert a1b2c3d… Original commit message
hint: After resolving the conflicts, mark them with
hint: "git add ", then run "git revert --continue"

Open the conflicted files, find the conflict markers (<<<<<<, ======, >>>>>>), resolve the conflict, stage the file, and continue:

git add resolved-file.js
git revert --continue

If you want to abandon the revert entirely:

git revert --abort

Real Example — The Midnight Hotfix Scenario

This one happens to almost every developer who’s been on a production team. It’s 11pm. Something broke on production. The breaking commit has already been pushed and pulled by three teammates. You need it gone in the next five minutes.

$ git log --oneline
f7e8d9c (HEAD -> main, origin/main) Deploy payment gateway integration
a1b2c3d Refactor checkout flow
e4f5g6h Add order confirmation email

[The payment gateway integration broke production. It needs to be undone NOW.]

$ git revert HEAD --no-edit
[main g8h9i0j] Revert "Deploy payment gateway integration"
3 files changed, 47 deletions(-)

$ git push origin main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 418 bytes | 418.00 KiB/s, done.
To https://github.com/company/app.git
f7e8d9c..g8h9i0j main -> main

[Production is back to working state in under 60 seconds. History preserved.
Teammates will pull the revert commit cleanly tomorrow morning. No conflicts.]

Side-by-Side Comparison: reset vs revert vs restore

Here’s the full picture in one place.

What it operates on:

git restore — Working directory and/or staging area
git reset — Branch pointer (commit history) and optionally staging area and working directory
git revert — Commit history (adds a new commit)

Does it rewrite history?

git restore — No (doesn’t touch history at all)
git reset — Yes (moves the branch pointer)
git revert — No (only adds to history)

Can you use it on shared/pushed branches?

git restore — Yes (it doesn’t affect history at all)
git reset — Only with force push, and only on branches you alone use
git revert — Yes, this is specifically what it’s designed for

Does it risk data loss?

git restore — Yes, if used without –staged on uncommitted working directory changes
git reset — Yes, with –hard flag
git revert — No (only adds a new commit; original commits remain)

Is the change reversible?

git restore — No (working directory changes that were never committed may be unrecoverable)
git reset — Yes, via git reflog for a limited time
git revert — Yes, by reverting the revert commit

Introduced in Git version:

git restore — Git 2.23 (2019)
git reset — Original Git (2005)
git revert — Original Git (2005)


The Decision Framework — Which One Do You Actually Need?

The Decision Framework — Which One Do You Actually Need?

When something has gone wrong and you’re deciding which command to use, work through this decision tree:

Question 1: Are you working with changes that haven’t been committed yet?

Yes — Use git restore.

  • Changes are in the working directory and you want to discard them: git restore filename
  • Changes are staged and you want to unstage them: git restore –staged filename
  • You want to discard both staged and working directory changes: git restore –staged –worktree filename

No, you’re dealing with commits — go to Question 2.

Question 2: Has the commit you want to undo been pushed to a shared branch?

Yes, it’s been pushed and others may have it — Use git revert.

  • Undo the last commit: git revert HEAD
  • Undo a specific older commit: git revert COMMIT-HASH
  • Push the revert normally: git push origin main

No, it’s only local (or only on your personal branch) — Use git reset.

  • Want to keep changes staged: git reset –soft HEAD~1
  • Want to keep changes unstaged: git reset HEAD~1
  • Want to discard changes entirely: git reset –hard HEAD~1

The one-sentence version of this decision: restore for uncommitted changes, reset for unpushed commits, revert for pushed commits.


Common Mistakes and Misconceptions

Mistake 1 — Using git reset on a shared branch

This is the mistake that causes the most team friction. Resetting commits that others have pulled creates a diverged history. Everyone who has the original commit will see conflicts the next time they try to push. The fix for this is always git revert — it achieves the same end result (the bad code is gone) without rewriting the shared history.

Mistake 2 — Using git restore to “undo a commit”

git restore doesn’t know about commits in the sense of undoing them. Running git restore on a file that was committed will restore the file to its state at the last commit — but the commit itself is still there. To undo a commit, you need reset or revert.

Mistake 3 — Assuming git reset –hard is always dangerous

git reset –hard is dangerous only if you run it when you have uncommitted work you care about. On a clean working directory — no staged changes, no working directory modifications — git reset –hard HEAD~1 is exactly as safe as git reset –soft HEAD~1. The difference is only relevant if you have uncommitted changes at the time you run it.

Mistake 4 — Using git checkout — filename instead of git restore

Before Git 2.23, git checkout — filename was the way to discard working directory changes. It still works — Git maintained backward compatibility. But it’s confusing because git checkout also switches branches. If you mistype or misunderstand the syntax, you might switch branches instead of restoring a file. git restore is explicit, readable, and does exactly what it says. Prefer it over the old checkout syntax for file operations.

Mistake 5 — Force pushing after a reset without warning teammates

Even if force push is the right technical action (you’re on your own branch, you’ve reset and want to update the remote), doing it without any communication can cause confusion. If a teammate happened to pull your branch earlier, they’ll hit a conflict the next time they try to push. A quick message — “heads up, I force pushed on feature/login” — saves everyone a debugging session.

Mistake 6 — Not using git reflog after an accidental git reset –hard

A lot of developers write off work as lost after running git reset –hard, not knowing that git reflog often has a path to recovery. The reflog records every position HEAD has been in for the past 30-90 days. Run git reflog immediately after any accidental hard reset — the commit you lost is very likely still accessible.

git reflog
[Find the hash of the commit you want to recover]
git reset –hard RECOVERED-COMMIT-HASH


Practical Scenarios — Matching the Right Command to the Real Situation

These are situations every developer encounters. Here’s the right tool for each one.

Scenario: You edited a file, decided you don’t want the changes, and the file hasn’t been staged.

Command: git restore filename.js
Why: Discards working directory changes for that file. Clean and targeted.

Scenario: You ran git add by mistake and want to unstage a file without losing the changes.

Command: git restore –staged filename.js
Why: Moves the file out of the staging area back to the working directory. Changes are preserved.

Scenario: You committed with a typo in the message and haven’t pushed yet.

Command: git commit –amend -m “Corrected message”
Why: Replaces the last commit with a corrected one. (Technically not one of our three commands, but it’s the right tool here.)

Scenario: You committed to the wrong branch and haven’t pushed.

Command: git reset –soft HEAD~1, then stash, checkout correct branch, pop, recommit.
Why: reset –soft removes the commit but keeps changes staged for the move.

Scenario: You made three WIP commits and want to squash them into one before a PR.

Command: git reset –soft HEAD~3, then git commit -m “Clean single commit”
Why: Collapses three commits into a clean staging area ready for one good commit.

Scenario: A bad commit was pushed to main and is breaking production right now.

Command: git revert HEAD, then git push
Why: Fastest path to undoing the damage without rewriting shared history or disrupting teammates.

Scenario: A bug was introduced five commits ago in a commit that only touched one file.

Command: git revert COMMIT-HASH
Why: Creates a targeted inverse of that specific commit without affecting the five commits after it.

Scenario: You want to see what a file looked like two commits ago without checking out the whole commit.

Command: git restore –source=HEAD~2 filename.js
Why: Restores just that one file from two commits back. Working directory only, no history changes.

Scenario: You ran git reset –hard and immediately regret it.

Command: git reflog, find the hash, git reset –hard THAT-HASH
Why: The reflog keeps a record of where HEAD was before the reset. Recovery is possible if done quickly.


Real Terminal Example — All Three Commands in One Session

This example shows a realistic development session where all three commands come up naturally.

$ git status
On branch feature/notifications
Changes to be committed:
modified: notifications.js
modified: debug-log.js
Changes not staged for commit:
modified: config.js

[debug-log.js should not be staged — that’s debug code]

[config.js changes were experimental — don’t want them at all]

$ git restore –staged debug-log.js

[debug-log.js unstaged — changes still in working directory]

$ git restore config.js

[config.js working directory changes discarded — back to last committed version]

$ git status
On branch feature/notifications
Changes to be committed:
modified: notifications.js
Changes not staged for commit:
modified: debug-log.js

$ git commit -m “Implement notification batching”
[feature/notifications a1b2c3d] Implement notification batching

[Later — realized the notification batching has a timing bug that affects production]
[This commit was pushed and teammates have pulled it already]

$ git revert HEAD –no-edit
[feature/notifications b2c3d4e] Revert “Implement notification batching”
1 file changed, 23 deletions(-)

$ git push origin feature/notifications
To https://github.com/company/app.git
a1b2c3d..b2c3d4e feature/notifications -> feature/notifications

[Revert pushed cleanly — no force push needed, teammates will pull it normally]

[Meanwhile, on another task — made three rough commits exploring an approach]

$ git log –oneline
b2c3d4e (HEAD -> feature/notifications) Revert “Implement notification batching”
a1b2c3d Implement notification batching
d3e4f5g WIP: trying websockets
c2d3e4f WIP: experimenting with polling
b1c2d3e WIP: started notification system
a0b1c2d Base notification structure

[The three WIP commits are messy — squash them before review]

$ git reset –soft HEAD~3
[Three commits gone, all changes staged]

$ git commit -m “Add notification system foundation with polling”
[feature/notifications e4f5g6h] Add notification system foundation with polling

[All three commands used appropriately in one realistic session]


Prevention Tips — Habits That Reduce the Need for Undo Commands

Tip 1 — Review Before You Commit, Every Single Time

The habit of running git diff –staged before every git commit catches most mistakes before they become commits. It adds ten seconds to your workflow and saves you from reaching for undo commands in the first place.

git diff –staged

Tip 2 — Use git add -p for Surgical Staging

git add -p stages changes interactively, chunk by chunk. You see each change and decide individually whether to stage it. This is the cleanest way to avoid committing debug code, unfinished experiments, or unrelated changes in the same commit.

git add -p

Tip 3 — Commit Small and With Purpose

Every commit should have exactly one reason to exist. If you find yourself writing a commit message with the word “and” in it (“Fix login bug and update styles and add tests”), that’s a signal the commit should be split. Smaller commits are easier to revert precisely. A revert of a well-scoped commit is clean. A revert of a sprawling commit risks undoing unrelated work.

Tip 4 — Use Feature Branches Generously

On a feature branch, you have the freedom to reset, squash, rebase, and rewrite history as much as you like — because you’re the only one using it. All the history cleanup happens before the branch is merged into main. The cleaner your feature branch history is when it’s reviewed, the less likely something ends up in main that needs reverting later.

Tip 5 — Write Descriptive Commit Messages

A good commit message is the difference between “git revert a1b2c3d” making immediate sense and requiring ten minutes of archaeology to figure out what you’re reverting and why. Every commit message should say what changed and why — not just what changed.

Bad: “Update stuff”
Good: “Remove rate limiting on API for internal dashboard endpoints”

When someone needs to revert that commit at 11pm in a production incident, they’ll thank you for the second version.

Tip 6 — Know Your Reflog Is There

git reflog is the safety net under all of Git’s undo operations. It records every position your HEAD has been in for the past 30-90 days. Before panicking about lost work, always check the reflog. The mental security of knowing it exists will also make you less hesitant to use reset when it’s the right tool — you know recovery is possible.

git reflog


FAQ

Q: I keep seeing git checkout used for things that git restore does now. Are they the same?

They overlap but aren’t the same. git checkout is a multi-purpose command that does different things depending on how you use it. Before Git 2.23, git checkout — filename was the way to discard working directory changes (equivalent to git restore filename today), and git checkout COMMIT-HASH — filename was the way to restore a file from a specific commit (equivalent to git restore –source=COMMIT-HASH filename today). Git 2.23 introduced git restore specifically to make file restoration operations more explicit and less confusing. Both old and new syntax work, but git restore is clearer and recommended for new work.

Q: When would I use git revert on a really old commit, not just the most recent one?

More often than you’d think. A common scenario: a feature was added three months ago, worked fine at the time, but is now causing a compliance or security issue that requires it to be removed. You can’t just delete the code in a regular commit because you need to ensure all the changes that feature introduced are cleanly reversed. git revert COMMIT-HASH applies the inverse of exactly that commit — nothing more, nothing less. It’s surgical in a way that manually deleting code isn’t.

Q: Does git revert work on merge commits?

Yes, but it requires an extra flag. When reverting a merge commit, Git needs to know which parent of the merge to treat as the “mainline” — i.e., which side of the merge you want the codebase to look like after the revert. Use -m 1 to specify the first parent (the branch you merged into):

git revert -m 1 MERGE-COMMIT-HASH

After the revert, note that the branch you merged is now “poisoned” from Git’s perspective — if you try to merge it again later, Git will see the changes as already reverted and won’t reapply them. This is a known gotcha with reverting merge commits that catches teams off guard.

Q: Can I use git restore to undo a git add?

Yes. git restore –staged filename unstages a file — the exact opposite of git add filename. The change stays in your working directory; it just moves out of the staging area. This is safe and has no effect on commit history.

Q: What’s the reflog and how long does it last?

The reflog is a local log Git keeps of every position your HEAD and branch pointers have been in. Every commit, reset, merge, rebase, and checkout is logged. Run git reflog to see it. Reflog entries are kept for 90 days by default (30 days for unreachable commits), after which they’re pruned by garbage collection. It’s local only — pushing to GitHub doesn’t push your reflog.

Q: Is there a way to do a “dry run” of git reset to see what would happen?

Not directly built into git reset, but you can simulate it. To see what git reset –soft HEAD~1 would affect without actually running it:

git log –oneline HEAD~3..HEAD

This shows the commits that would be affected. For a more detailed preview:

git diff HEAD~1 HEAD

This shows the changes that would become staged/unstaged after the reset.

Q: Why does git revert sometimes open a text editor?

By default, git revert opens your configured text editor (usually vim or nano, depending on your Git configuration) to let you write or edit the commit message for the revert commit. If you want to skip this step and use the auto-generated message (“Revert ‘original message'”), add –no-edit:

git revert HEAD –no-edit

To change which editor Git uses (permanently):

git config –global core.editor “code –wait”

This sets VS Code as the default editor.

Q: I used git reset and now git push is rejected. Did I break something?

Not permanently. After a reset, your local branch has fewer commits than the remote, so a normal push would delete commits from the remote — something Git refuses to do automatically. If you’re on a personal branch:

git push –force origin your-branch-name

If you’re on a shared branch and ran reset by mistake, the cleanest recovery is to git pull (to re-sync with the remote) and then use git revert on the commits you want to undo instead.

Q: What’s the practical difference between git reset –soft and git stash?

Both preserve your changes. The difference is scope and intent. git reset –soft operates at the commit level — it undoes a commit and leaves those changes staged. git stash operates at the working directory and staging area level — it saves your current uncommitted changes and gives you a clean working directory without touching commits. They’re often used together: reset –soft to undo a commit, then stash to temporarily move those changes while you switch branches.


Related Errors and Situations

error: Your local changes would be overwritten

Appears when you try to run git reset or git restore while you have uncommitted changes that would be overwritten. Stash your work first:

git stash
git reset HEAD~1
git stash pop

fatal: ambiguous argument ‘HEAD~1’

Appears when you try to reset on a repository that only has one commit. There’s no HEAD~1 to go back to. For a fresh repository, use:

git rm –cached -r .

error: pathspec ‘filename’ did not match any file(s) known to git

Appears with git restore when the filename doesn’t match exactly (check capitalization, file extension, path). Make sure you’re in the right directory and the file is tracked by Git.

HEAD detached at COMMIT-HASH

If you ran git checkout COMMIT-HASH instead of git restore –source=COMMIT-HASH, you’ve detached HEAD. Return to your branch:

git checkout main

CONFLICT during git revert

A revert conflict means the file has changed since the commit you’re reverting. Resolve manually, stage the resolved file, then:

git revert –continue

Changes don’t appear after git restore –staged

If you ran git restore –staged but the file still appears staged, verify you’re using the correct filename (case-sensitive) and that the file is actually in the staging area (git status).


Conclusion

If there’s one thing to take away from this entire guide, it’s this: the confusion between reset, revert, and restore comes from treating them as interchangeable undo buttons when they’re actually three distinct tools for three different situations.

git restore is for file-level operations. Uncommitted changes you want to discard or unstage. It doesn’t know about commits in any meaningful sense. It’s also the one that can cause quiet, unrecoverable data loss if you use it carelessly on files that have never been committed.

git reset is for personal history cleanup. Squashing WIP commits before a PR, undoing a commit that went to the wrong branch, going back to a clean state for local work you haven’t shared. It rewrites history — which is fine when the history is yours alone, and a team headache when it isn’t.

git revert is for shared work. When code has been pushed, when teammates have pulled, when the history has to stay intact — this is the only responsible choice. It’s slower in the sense that it adds a commit rather than removing one, but that slowness is the point. The deliberateness of a revert commit is what makes it safe.

The mental shortcut: restore for files, reset for private commits, revert for public commits.

And if you ever run a hard reset and feel that stomach drop — check git reflog immediately. Git keeps a record of where you’ve been. The work is very likely still there, waiting to be recovered. That’s not a coincidence. It’s a reflection of a tool designed by people who understood that developers make mistakes, need room to experiment, and deserve the ability to recover gracefully.

That’s Git at its best — not a rigid audit trail, but a thoughtful system for navigating the very human process of writing and refining code.


Related Resources

Git Official Documentation — git-restore

Git Official Documentation — git-reset

Git Blogs – collection of git related blogs from prodopshub.com


About the Author

Kedar Salunkhe

DevOps Engineer | Seven years of fixing things that break at 2am
Kubernetes • OpenShift • AWS • Coffee

I’ve spent almost 7 years keeping production systems running, often when everyone else is asleep. These days I’m working with Kubernetes and OpenShift deployments, automating everything that can be automated, and occasionally remembering to document the things I fix. When I’m not troubleshooting clusters, I’m probably trying out new DevOps tools or explaining to someone why we can’t just “restart everything” as a debugging strategy. You can usually find me where the coffee is strong and the error logs are confusing.

And if this guide helped untangle something that’s been confusing for a while — share it with the person on your team who you know has been avoiding these commands. They deserve to have the stomach drops too.

Leave a Comment