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.