# How to undo commits in Git (locally and on GitHub) and recover “lost” files with reflog
It happens to everyone: you make a commit, push it to GitHub, realize something shouldn’t be there… and while trying to fix it you end up “losing” a file or a commit.
Good news: **Git almost always has a way out** (especially if you use `reflog`).
In this post you’ll learn:
- How to **undo the last commits** locally and on GitHub
- The difference between **reset** and **revert**
- How to **recover commits** after a `reset --hard`
- How to **restore a specific file** from an earlier commit
- How to **change the last commit message**
- A real example with commands and terminal output
---
## 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
### Option A: `reset` (rewrites history)
Useful when you want those commits to **disappear from the history**.
- **Deletes commits and discards changes** (hard mode):
```bash
git reset --hard HEAD~2
- Deletes commits but keeps changes staged (soft mode):
git reset --soft HEAD~2
If you already pushed to GitHub, to make the remote match you must force push:
git push --force-with-lease origin YOUR_BRANCH
Example:
git push --force-with-lease origin master
✅ --force-with-lease is safer than --force because it prevents overwriting remote changes you don’t have locally.
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
2) Recover commits after reset --hard with reflog
If you ran:
git reset --hard HEAD~1
and then regretted it, your lifeline is:
git reflog
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
You can see the “lost” commit still exists: 3bfb189.
To return to that state:
git reset --hard 3bfb189
If you also want GitHub to match:
git push --force-with-lease origin master
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>
Common example: restore .gitignore from 3bfb189:
git restore --source 3bfb189 -- .gitignore
Then save it in history:
git add .gitignore
git commit -m "chore: restore .gitignore"
git push origin master
“I don’t know the exact file path…”
First, list the files touched by that commit:
git show --name-status --pretty="" 3bfb189
Or list everything that exists in that commit:
git ls-tree -r 3bfb189 --name-only
Once you find the exact path, restore it:
git restore --source 3bfb189 -- real/path/to/file.ext
Restore EVERYTHING from a commit (warning: overwrites)
If you truly want to bring everything back exactly as it was in that commit:
git restore --source 3bfb189 -- .
4) Change the last commit message
If you have NOT pushed yet
git commit --amend -m "new message"
If you ALREADY pushed to GitHub
git commit --amend -m "new message"
git push --force-with-lease origin YOUR_BRANCH
Example:
git push --force-with-lease origin master
5) Tips to avoid Git pain (seriously)
- Before doing an aggressive reset, create a “backup branch”:
git branch backup-before-reset
- Prefer
--force-with-leaseover--force - If you’re working with a team, prefer
revertoverreset -
reflogis your “secret history”: when something “disappears”, checkgit reflog
Wrap-up
If you ever feel like you “lost” commits or files, remember:
-
git reflogfinds the commit you can’t see anymore -
git restore --sourcerestores specific files without breaking everything -
resetrewrites history (requires force push) -
revertis team-friendly























