Reset: Soft vs Mixed vs Hard
Hard reset se pehle hamesha sochna — uncommitted data wapas nahi aata.
git reset moves the current branch pointer (HEAD of your branch) to a different commit. That is its primary function.
The three modes — --soft, --mixed, --hard — control what ELSE happens to the staging area and working directory.
Think of three areas: 1) Repository (where commits live), 2) Staging Area / Index (what will go in next commit), 3) Working Directory (your actual files).
git reset ALWAYS moves the branch pointer in the repository. The question is: what happens to staging and working directory?
After reset, your branch points to the specified commit. The commits that were between the old and new position become "unreachable" (but still exist in reflog).
# Setup: 3 commits
echo "v1" > file.txt && git add . && git commit -m "v1"
echo "v2" >> file.txt && git add . && git commit -m "v2"
echo "v3" >> file.txt && git add . && git commit -m "v3"
git log --oneline
# c3d4e5f (HEAD -> main) v3
# b2c3d4e v2
# a1b2c3d v1
# All 3 modes move main from c3d4e5f to b2c3d4e
# But they differ in what happens to staging and working dir
# Current state before reset:
# Repository: v3 (main points here)
# Staging: matches v3
# Working: matches v3git reset --soft HEAD~1 moves the branch pointer back, but keeps ALL changes staged.
Repository: branch moves back to v2. Staging: changes from v3 are still staged. Working: unchanged.
Use case: "I committed too early. I want to add more changes to this commit."
Use case: "I want to combine the last few commits into one." (soft reset + recommit)
The changes from the undone commits appear as if you just git add-ed them. They are ready to commit again.
This is the SAFEST reset — you lose nothing. Changes are staged and ready to go.
# After: git reset --soft HEAD~1
# Repository: v2 (main moved back)
# Staging: changes from v3 are STILL STAGED
# Working: matches staging
git status
# Changes to be committed:
# modified: file.txt
# (v3 changes are staged and ready!)
git diff --staged
# Shows the v3 changes — they're staged!
# You can now add more changes and commit
echo "v3-extra" >> file.txt
git add .
git commit -m "v3 with extra changes"
# Combines old v3 + new changes in one commit
# Or just recommit the same changes
git commit -m "v3 again"git reset --mixed HEAD~1 (or just git reset HEAD~1) moves the branch pointer back AND unstages the changes.
Repository: branch moves back to v2. Staging: reset to match v2 (changes unstaged). Working: changes are still in your files.
Use case: "I accidentally staged files I don't want to commit yet." (unstage without losing work)
Use case: "I want to undo the commit and review the changes before re-staging."
This is the DEFAULT mode when you don't specify --soft or --hard.
Changes are in your working directory but not staged. You must git add them again before committing.
# After: git reset --mixed HEAD~1
# (same as: git reset HEAD~1)
# Repository: v2 (main moved back)
# Staging: matches v2 (v3 changes are UNSTAGED)
# Working: v3 changes still in your files
git status
# Changes not staged for commit:
# modified: file.txt
# (v3 changes are in working dir but NOT staged)
git diff
# Shows the v3 changes — they're unstaged
# You must re-stage before committing
git add file.txt
git commit -m "v3 properly"
# Or selectively stage parts
git add -p file.txt
git commit -m "v3 partial"git reset --hard HEAD~1 moves the branch pointer back, unstages changes, AND DELETES them from your working directory.
Repository: branch moves back to v2. Staging: reset to match v2. Working: ALL changes from v3 are DELETED.
Use case: "I completely messed up. I want to go back to the last known good state."
This is the DANGEROUS reset. Uncommitted changes are DESTROYED. They cannot be recovered by normal Git commands.
The COMMITS are still recoverable via reflog for 90 days. But UNCOMMITTED working directory changes are GONE FOREVER.
Rule: NEVER use --hard if you have uncommitted changes you want to keep. Always git stash first.
# After: git reset --hard HEAD~1
# Repository: v2 (main moved back)
# Staging: matches v2
# Working: matches v2 — v3 changes are DELETED
git status
# nothing to commit, working tree clean
# (v3 changes are GONE from everywhere!)
cat file.txt
# v1
# v2
# (v3 line is gone!)
# RECOVERY (if you committed v3 before reset):
git reflog
# c3d4e5f HEAD@{1}: commit: v3 ← old commit still exists!
git reset --hard c3d4e5f # recover!
# NO RECOVERY for uncommitted changes:
echo "important uncommitted work" >> file.txt
git reset --hard HEAD
# "important uncommitted work" is GONE FOREVER
# Not in reflog, not in objects — nowhere
git stash to save them temporarily. Once --hard runs, uncommitted changes are permanently destroyed. The reflog can recover COMMITTED changes, but uncommitted work is beyond Git's reach — it was never stored as an object.git reset moves the branch pointer backward. Use on YOUR local branches that haven't been shared.
git revert creates a NEW commit that undoes a previous commit. Use on SHARED/PUBLIC branches.
git checkout switches branches or restores files. It does NOT move branch pointers.
Never reset a branch that others are using — it creates divergent histories that cause chaos when they try to push/pull.
git reset HEAD <file> = unstage a specific file (doesn't change commits).
git checkout -- <file> = discard working directory changes (doesn't change commits).
# Summary comparison
# UNDO last commit, keep changes staged (safest)
git reset --soft HEAD~1
# UNDO last commit, keep changes unstaged (default)
git reset --mixed HEAD~1
git reset HEAD~1 # same thing
# UNDO last commit, DELETE changes (dangerous!)
git reset --hard HEAD~1
# UNDO a pushed commit safely (creates undo commit)
git revert <hash>
# UNSTAGE a file (doesn't affect commits)
git reset HEAD file.txt
# DISCARD working directory changes (doesn't affect commits)
git checkout -- file.txt
git restore file.txt # modern equivalent
# SWITCH branches (doesn't affect commits)
git checkout other-branch
git switch other-branch # modern equivalent
Lo kar liya — Key Points:
- ✅ git reset moves the current branch pointer to a different commit — that is its primary function
- ✅ --soft moves the branch pointer but keeps all changes STAGED — safest reset, nothing lost
- ✅ --mixed (default) moves the branch pointer and UNSTAGES changes — changes stay in working directory
- ✅ --hard moves the branch pointer, unstages changes, AND DELETES them from working directory — dangerous
- ✅ After --hard, COMMITTED changes are recoverable via reflog, but UNCOMMITTED changes are gone forever
- ✅ Use reset on local/private branches, use revert on shared/public branches
- ✅ Always stash or commit before using --hard — it destroys uncommitted work without warning
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login