You made commits you regret. Maybe the commitWhat is commit?A permanent snapshot of your staged changes saved in Git's history, identified by a unique hash and accompanied by a message describing what changed. message was wrong. Maybe you included files you should not have. Maybe you want to split one big commit into several smaller ones. Git reset is the time machine that lets you undo commits, but it comes in three modes with very different consequences.
Understanding the difference between soft, mixed, and hard reset is critical because one of them destroys data permanently while the other two are completely safe.
git reset --hard as the first solution for almost any undo scenario. They treat it as a quick fix, but --hard permanently deletes uncommitted work. In most cases, --soft or --mixed does what you actually need without any data loss.The three modes of git reset
Think of the three modes as levels of intensity:
| Mode | HEAD moves | Staging area | Working directory | Data loss |
|---|---|---|---|---|
--soft | Yes | Unchanged (staged) | Unchanged | No |
--mixed | Yes | Reset (unstaged) | Unchanged | No |
--hard | Yes | Reset | Reset to match HEAD | Yes, permanent |
Soft reset: undo commitWhat is commit?A permanent snapshot of your staged changes saved in Git's history, identified by a unique hash and accompanied by a message describing what changed., keep changes staged
git reset --soft HEAD~1This moves HEADWhat is head?A special pointer in Git that indicates the commit you are currently working on - usually the tip of the active branch. back one commit but leaves all changes from that commit in the staging areaWhat is staging area?A holding zone in Git where you place changes you want to include in your next commit, letting you select exactly which modifications to save., ready to be recommitted. Nothing is lost.
Use case: fix a commit message or add a forgotten file
# You committed but forgot to add the tests
git reset --soft HEAD~1
# All changes are still staged
git add auth.test.js
# Commit everything together with a better message
git commit -m "feat: add user authentication with tests"Mixed reset: undo commit, unstage changes
git reset HEAD~1
# or explicitly
git reset --mixed HEAD~1This moves HEAD back and unstages the changes, but keeps them in your working directory. Nothing is lost.
Use case: split a big commit into smaller ones
# You made one messy commit with everything
git reset HEAD~1
# Changes are now unstaged - stage and commit selectively
git add auth.js
git commit -m "feat: implement JWT authentication"
git add styles.css
git commit -m "style: update login form styling"
git add README.md
git commit -m "docs: add authentication setup instructions"Hard reset: undo commit and destroy all changes
git reset --hard HEAD~1This is the nuclear option. It moves HEAD back, clears the staging area, and resets your working directory to match. All changes are permanently deleted.
git reset --hard is irreversible. Once you run it, changes are gone from your working directory, staging area, and commit history. The only recovery path is if you find the old commit hash in git reflog before garbage collection runs. Never use --hard unless you are 100% certain you do not need those changes.The only safe use cases for --hard:
- You truly want to discard an experiment and start fresh
- You committed sensitive data (passwords, APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. keys) and want it gone
- You are absolutely certain you do not need the changes
Understanding HEADWhat is head?A special pointer in Git that indicates the commit you are currently working on - usually the tip of the active branch. references
| Reference | Meaning |
|---|---|
HEAD | Current commit |
HEAD~1 or HEAD^ | One commit before HEAD |
HEAD~2 | Two commits before HEAD |
HEAD~3 | Three commits before HEAD |
abc1234 | Specific commit by hash |
# Go back 1 commit
git reset --soft HEAD~1
# Go back 3 commits
git reset --mixed HEAD~3
# Go to a specific commit
git reset --hard abc1234The golden rule: never reset shared history
Git reset rewrites history. This is fine for local, unpushed commits. It is catastrophic for shared, pushed commits.
# DANGEROUS: resets pushed commits
git reset --hard HEAD~3
git push --force # Destroys work others depend onIf other people have pulled those commits and built on them, your force pushWhat is force push?A destructive Git push that overwrites the remote branch history with your local version, which can break teammates' work if they already pulled the original. creates chaos. For anything that has been pushed, use git revert instead, which creates new commits that undo changes without rewriting history.
Unstaging files with reset
A common use of git reset that has nothing to do with commits:
# You accidentally staged a sensitive file
git add config.env # Oops
# Unstage it (keep the modifications)
git reset HEAD config.env
# Modern alternative (clearer intent)
git restore --staged config.envThis does not move HEADWhat is head?A special pointer in Git that indicates the commit you are currently working on - usually the tip of the active branch. or affect commits. It just removes files from the staging areaWhat is staging area?A holding zone in Git where you place changes you want to include in your next commit, letting you select exactly which modifications to save..
Quick reference
| Use case | Command |
|---|---|
| Fix commit message | git reset --soft HEAD~1 then git commit |
| Add forgotten file to last commit | git reset --soft HEAD~1, git add file, git commit |
| Split a commit into smaller ones | git reset HEAD~1 then selective git add and git commit |
| Combine multiple commits | git reset --soft HEAD~n then git commit |
| Unstage a file | git reset HEAD file or git restore --staged file |
| Discard everything (dangerous) | git reset --hard HEAD~1 |