đ° 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 repositorychore: 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
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
- Deletes commits but keeps changes staged (soft mode):
git reset --soft HEAD~2
Example:
git push --force-with-lease origin master
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 YOUR_BRANCH
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 YOUR_BRANCH
Or list everything that exists in that commit:Donât know the exact file path?
List the files touched by that commit:
git show --name-status --pretty="" 3bfb189
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)
â ď¸ This can overwrite local changes in your working tree:
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
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
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)