Synopsis
git reset [--soft | --mixed | --hard] [<commit>]
git reset [<commit>] [--] <pathspec>...
Description
The git reset command moves the current branch pointer to a specified commit, optionally updating the index and working tree. It has three primary modes: --soft (move HEAD only), --mixed (default; also reset the index), and --hard (also reset the working tree, discarding all changes).
Reset is one of the most powerful and most dangerous Git commands. git reset --hard can permanently lose work — though git reflog usually allows recovery within the reflog window. With path arguments, reset operates only on the index for those paths and never moves HEAD.
In day-to-day use, git reset integrates closely with shell aliases, editor plugins, and continuous integration. Power users often add aliases that combine flags they always pass, or wrap the command in scripts that enforce team conventions. Output formatting can be customized via Git config — pretty formats, color schemes, and pager behavior are all tunable. When something goes wrong, the first diagnostic step is usually to re-run the command with GIT_TRACE=1 in the environment, which reveals the underlying plumbing calls. For unusual situations, the --help output (git reset --help) opens the full manual page with details on every option, including those rarely used in casual workflows but essential for debugging or scripting at scale.
Understanding how git reset interacts with the rest of Git's data model — the object database, the index, refs, and the working tree — pays dividends. Each command operates on some subset of these pieces, and knowing which it touches helps predict outcomes and recover from mistakes. Reading the official Git documentation alongside hands-on practice in a throwaway repository is the fastest way to internalize the nuances. Most production issues with Git stem from one of three causes: surprising default behavior, partial network operations, or rewriting history that was already shared. A working mental model of git reset's side effects helps avoid all three.
Common Options
| Option | Description |
|---|---|
--soft | Move HEAD only; index and working tree unchanged. |
--mixed (default) | Move HEAD and reset the index; working tree unchanged. |
--hard | Move HEAD, reset index, and overwrite working tree. |
--keep | Like --hard, but abort if local changes would be lost. |
--merge | Reset the index and updates files that differ between HEAD and target, keeping local merges. |
-p | Interactively select hunks to unstage. |
Examples
git reset HEAD~1
# Move back one commit; keep changes in working tree
git reset --soft HEAD~3
# Combine the last 3 commits into a single staged change
git reset --hard origin/main
# Discard ALL local commits and changes (dangerous)
git reset HEAD config.yml
# Unstage a single file (older syntax for git restore --staged)
Common Mistakes
git reset --hard on a branch with unpushed commits loses them. Reflog can save you within ~90 days, but only if you know to look. Confusing git reset HEAD file (unstage) with git reset --hard (nuke) is a classic beginner footgun. Modern Git provides git restore --staged as a clearer alternative.
Related Commands
git restore, git revert, git reflog, git stash