DEV Community

Cover image for Reset, revert, and reflog: the ultimate guide to undoing commits without losing your repo
Cristian Jonhson Alvarez
Cristian Jonhson Alvarez

Posted on

Reset, revert, and reflog: the ultimate guide to undoing commits without losing your repo

😰 Story time: I ran git reset --hard HEAD~1, force pushed… and then realized I needed that file back.

TL;DR

  • Not pushed yet → reset
  • Pushed + shared branch → revert
  • “Lost” a commit → git reflog

The real-world scenario

You’re working on a repo and you create commits like:

  • chore: remove compiled artifacts from the repository
  • chore: add .gitignore to exclude unnecessary files

Then you try to undo the last commit, you run push --force-with-lease, and later you say:

“I need to recover that file.”

Let’s go step by step.


1) Undo the last commits: reset vs revert

Rule of thumb:

  • ✅ Working alone / not pushed yet → use reset
  • 👥 Shared branch / already pushed → use revert

Before you copy/paste commands, get your current branch name:

git branch --show-current
Enter fullscreen mode Exit fullscreen mode

Use that value wherever you see YOUR_BRANCH.

Option A: reset (rewrites history)

Useful when you want those commits to disappear from the history.

  • Deletes commits and discards changes (hard mode):
git reset --hard HEAD~2
Enter fullscreen mode Exit fullscreen mode
  • Deletes commits but keeps changes staged (soft mode):
git reset --soft HEAD~2
Enter fullscreen mode Exit fullscreen mode

GitHub note (force push): If you already pushed, to make the remote match you must force push.

Avoid --force and use:
git push --force-with-lease origin YOUR_BRANCH
Enter fullscreen mode Exit fullscreen mode

✅ --force-with-lease is safer because it won’t overwrite remote work you don’t have locally.

⚠️ If the branch is protected (common on main/master), GitHub may block force pushes.

Example:

git push --force-with-lease origin master
Enter fullscreen mode Exit fullscreen mode

Option B: revert (does NOT rewrite history)

Recommended when:

  • Other people are working on the repo
  • The branch is shared
  • The branch is protected (e.g., main/master)

It creates new commits that undo the changes:

git revert --no-edit HEAD~2..HEAD
git push origin YOUR_BRANCH
Enter fullscreen mode Exit fullscreen mode

2) Recover commits after reset --hard with reflog

If you ran:

git reset --hard HEAD~1
Enter fullscreen mode Exit fullscreen mode

and then regretted it, your lifeline is:

git reflog
Enter fullscreen mode Exit fullscreen mode

Real example output:

dc65430 HEAD@{0}: reset: moving to HEAD~1
3bfb189 HEAD@{1}: commit: chore: add .gitignore to exclude unnecessary files
dc65430 HEAD@{2}: commit: chore: remove compiled artifacts from the repository
Enter fullscreen mode Exit fullscreen mode

You can see the “lost” commit still exists: 3bfb189.

To return to that state:

git reset --hard 3bfb189
Enter fullscreen mode Exit fullscreen mode

If you also want GitHub to match:

git push --force-with-lease origin YOUR_BRANCH
Enter fullscreen mode Exit fullscreen mode

3) Restore a specific file from an earlier commit

Sometimes you don’t want to move the whole branch—only recover one file that existed in a past commit.

Important

This command always requires a path:

git restore --source <COMMIT> -- <FILE_PATH>
Enter fullscreen mode Exit fullscreen mode

Common example: restore .gitignore from 3bfb189:

git restore --source 3bfb189 -- .gitignore
Enter fullscreen mode Exit fullscreen mode

Then save it in history:

git add .gitignore
git commit -m "chore: restore .gitignore"
git push origin YOUR_BRANCH
Enter fullscreen mode Exit fullscreen mode

Don’t know the exact file path?
List the files touched by that commit:
git show --name-status --pretty="" 3bfb189
Enter fullscreen mode Exit fullscreen mode

Or list everything that exists in that commit:

git ls-tree -r 3bfb189 --name-only
Enter fullscreen mode Exit fullscreen mode

Once you find the exact path, restore it:

git restore --source 3bfb189 -- real/path/to/file.ext
Enter fullscreen mode Exit fullscreen mode

Restore EVERYTHING from a commit (warning: overwrites)

⚠️ This can overwrite local changes in your working tree:

git restore --source 3bfb189 -- .
Enter fullscreen mode Exit fullscreen mode

4) Change the last commit message

If you have NOT pushed yet

git commit --amend -m "new message"
Enter fullscreen mode Exit fullscreen mode

If you ALREADY pushed to GitHub

git commit --amend -m "new message"
git push --force-with-lease origin YOUR_BRANCH
Enter fullscreen mode Exit fullscreen mode

5) Tips to avoid Git pain (seriously)

  • Before doing an aggressive reset, create a “backup branch”:
git branch backup-before-reset
Enter fullscreen mode Exit fullscreen mode
  • Prefer --force-with-lease over --force
  • If you’re working with a team, prefer revert over reset
  • reflog is your “secret history”: when something “disappears”, check git reflog

Wrap-up

If you ever feel like you “lost” commits or files, remember:

  • git reflog finds the commit you can’t see anymore
  • git restore --source restores specific files without breaking everything
  • reset rewrites history (requires force push)
  • revert is team-friendly

Your turn 👻

What’s your worst Git mistake? Did you manage to recover it, or did you have to start over? Drop your story in the comments.

Top comments (0)