iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

git reset

git reset moves HEAD (and optionally the index / working tree) to a chosen commit. Three modes: --soft, --mixed (default), --hard. The most-feared git command — with reflog, it’s recoverable.

Soft, mixed, hard, recovery

EXAMPLE
# 1) Three modes — same operation, different scope
#
# HEAD = pointer to current commit
# Index (staging) = what 'git commit' would record
# Working tree = your actual files
#
# --soft   : moves HEAD only; index + working tree untouched
# --mixed  : moves HEAD + index; working tree untouched (DEFAULT)
# --hard   : moves HEAD + index + working tree (DESTRUCTIVE)

# 2) Undo last commit, KEEP changes staged
git reset --soft HEAD~1
# Use case: you committed too soon; want to amend / add more

# 3) Undo last commit, KEEP changes UNSTAGED
git reset HEAD~1
# Or: git reset --mixed HEAD~1
# Use case: split a big commit into smaller ones; re-stage selectively

# 4) Undo last commit, THROW AWAY changes (DESTRUCTIVE)
git reset --hard HEAD~1
# Use case: committed broken code; want to start over
# Recovery: git reflog → find the old SHA → git reset --hard <SHA>

# 5) Reset to a specific commit
git reset --hard abc1234
git reset --hard origin/main         # match the remote exactly

# 6) Unstage specific files (without changing them)
git reset HEAD path/to/file.ts
git reset HEAD .                       # unstage everything
# Modern alias: git restore --staged <file>

# 7) Reset a file to a specific commit's state
git checkout abc1234 -- path/to/file.ts
# Or:
git restore --source=abc1234 path/to/file.ts

# === Reset vs revert vs checkout ===

# reset    : moves HEAD (rewrites history) — DESTRUCTIVE on shared branches
# revert   : creates a NEW commit that undoes a previous one — safe to push
# checkout : changes working tree to match a commit (without moving HEAD)

# When to use which:
#   - PRIVATE branch, want to redo: reset
#   - PUBLIC / shared branch: revert
#   - Just look at old state: checkout

# 8) Revert (safe alternative to hard reset on shared branches)
git revert abc1234
# Creates a new commit on top of HEAD that undoes abc1234.
# Safe to push; doesn't rewrite history.

git revert HEAD~3..HEAD                # revert last 3 commits
git revert --no-commit HEAD~3..HEAD    # group all into one new commit
git commit -m 'Revert features X, Y, Z'

# 9) Reflog — the safety net
git reflog
# 0a8c5d1 HEAD@{0}: reset: moving to HEAD~3
# 1b2c3d4 HEAD@{1}: commit: WIP feature
# 5e6f7g8 HEAD@{2}: commit: fix bug
# ...

# Recover from a 'lost' commit:
git reset --hard HEAD@{2}             # jump back to commit 5e6f7g8
# OR
git checkout 5e6f7g8                  # detached HEAD; cherry-pick what you need

# Reflog keeps entries for ~30 days by default.
# After that, git gc may collect them — usually still recoverable for a while.

# 10) Recover deleted files (if not committed)
# If you `git reset --hard` lost uncommitted work, it MIGHT be in 'git fsck':
git fsck --lost-found
ls .git/lost-found/other/             # dangling blobs
# Open each blob to see if it's your file.

# 11) Reset for branch alignment
# 'I want my branch to match origin/main exactly':
git fetch origin
git reset --hard origin/main
# This is a 'I give up; sync to upstream' move on a local branch.

# 12) Reset selectively — split a commit
git reset --soft HEAD~1                # uncommit, keep changes staged
git reset HEAD path/to/file1            # unstage file1 specifically
git commit -m 'just file2 + file3 change'
git add path/to/file1
git commit -m 'file1 change'

# Or use git rebase -i for interactive history editing.

# 13) Hard reset on a remote branch — DANGEROUS
# This requires --force-with-lease (or --force):
git reset --hard <SHA>
git push --force-with-lease            # refuses if remote moved

# Rules:
#   ✅ OK on private feature branches you own
#   ❌ NEVER on shared branches (main, develop, release/*)
#   ❌ NEVER on tagged commits

# 14) Common bugs
#   • `git reset --hard` on the wrong commit → lost changes
#       Recovery: git reflog → reset to the right SHA
#   • Used reset on a shared branch → teammates' next push rejected
#       Recovery: hard reset back to where it was, force-push
#   • Confusing reset with checkout — checkout HEAD~3 detaches HEAD; doesn't move it
#   • `--mixed` (default) leaves stuff in working tree that you might not realise → confused diffs

# 15) Modern aliases (since git 2.23)
git restore <file>                     # discard changes in working tree
git restore --staged <file>             # unstage
git restore --source=<commit> <file>    # restore from a specific commit
git switch <branch>                     # change branch (replaces checkout <branch>)
git switch -c <newbranch>               # create + switch
# These commands have CLEARER semantics than the overloaded `git reset` / `git checkout`.

# 16) Decision tree
#
# 'I want to undo my last commit BUT keep the changes':
#   - staged?     → git reset --soft HEAD~1
#   - unstaged?   → git reset HEAD~1
#   - delete?     → git reset --hard HEAD~1     (only if you don't need the changes)
#
# 'I pushed a bad commit to a shared branch':
#   - git revert <bad SHA>
#   - git push
#
# 'I lost work after a bad reset':
#   - git reflog
#   - git reset --hard HEAD@{N}
#
# 'I want my local branch to match the remote exactly':
#   - git fetch && git reset --hard origin/<branch>
#
# 'I want to discard ALL local changes':
#   - git reset --hard HEAD
#   - git clean -fd       (also remove untracked files + dirs)

Why it matters

The golden rule: --hard is recoverable via git reflog. --soft keeps your work staged; --mixed (default) leaves it in the working tree. Reach for git revert on shared branches — never reset + force-push there.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
git reset --soft HEAD~1    # uncommit, keep changes staged
git reset --mixed HEAD~1   # uncommit + unstage
git reset --hard HEAD~1    # destroy! (and the work)
Try it Yourself »

Exercise

Uncommit but keep changes staged.

git reset HEAD~1

Discussion

Loading…