C.W.K.
Stream
Lesson 02 of 05 · published

reset: Move Branch Pointers Carefully

~24 min · reset, head

Level 0Untracked Rookie
0 XP0/47 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

reset moves the branch pointer; the modes decide what else moves

git reset is the most powerful and most misused command in Git. Its core operation is simple: move the current branch's pointer to a different commit. The confusion comes from three modes that decide whether the index and working tree follow along. Knowing which mode for which intent removes 95% of reset-related disasters.

--soft moves the branch pointer only. Working tree and index untouched. The commits between the old tip and the new target become "uncommitted but staged" — exactly the state for combining several commits into one or for redoing the last commit cleanly. --mixed (default) moves the pointer and resets the index to match. Working tree untouched. Commits become "uncommitted, unstaged" — useful for completely reworking what gets staged. --hard moves the pointer, resets the index, AND overwrites the working tree to match. All uncommitted work in those affected files is gone. Powerful and dangerous.

The naming is unfortunate but stable. Memorize it once: soft = pointer-only, mixed = pointer + index, hard = pointer + index + worktree. Increasing destruction at each level. The most common useful invocations: git reset --soft HEAD~1 to undo the last commit while keeping its changes staged for amendment; git reset HEAD~3 (mixed) to unstage and rework the last three commits; git reset --hard origin/main when you want your branch to mirror the remote exactly.

Reset rewrites local history. If those commits have not been pushed, no problem. If they have been pushed and others have based work on them, you have moved a published commit and the path forward is force-push gymnastics. The general rule: reset is for unpublished history. For published history, the answer is git revert, covered next lesson.

Code

Three modes, three intents·bash
# Undo last commit, keep its changes staged for amendment:
git reset --soft HEAD~1
# now you can re-commit with a better message or split the change.

# Unstage the last 3 commits' changes back into working tree:
git reset HEAD~3                # implicit --mixed

# DESTRUCTIVE — branch + index + worktree all rewind 1 commit:
git reset --hard HEAD~1

# Rewind to match the remote exactly (lose any local extras):
git fetch origin
git reset --hard origin/main
Recover from a bad reset·bash
# Just did git reset --hard and lost commits?
git reflog                       # find the lost tip in the reflog

# Reflog shows entries like:
# abc1234 HEAD@{0} reset: moving to HEAD~3
# def5678 HEAD@{1} commit: feature/x done

# Restore the lost tip onto a rescue branch:
git switch -c rescue def5678

# Or move main itself back:
git reset --hard def5678

External links

Exercise

On a scratch branch, make three commits. Try each of the three reset modes against HEAD~2: soft, mixed (default), hard. Between each test, undo with git reset --hard ORIG_HEAD or by recovering from git reflog. After each mode, run git status and write down what was preserved and what was discarded.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.