git reset Explained
git reset is one of the most powerful and most misunderstood commands in Git because it does two conceptually separate things depending on how it's invoked: it moves where the current branch pointer (HEAD) points to, and — depending on the mode — it can also rewrite the staging area (the index) and the working directory to match. Used carefully, reset is how you unstage files, undo local commits, or throw away uncommitted changes entirely. Used carelessly, particularly with --hard, it is how people lose work, because --hard overwrites the working directory with no confirmation and no automatic backup.
Cricket analogy: Like a scorer who can move the innings marker back to an earlier over while keeping every run already noted (careful use), but hitting the "wipe the entire scoresheet" option instantly erases all runs scored since with no undo and no backup copy saved anywhere.
The three modes
git reset --soft <commit> moves HEAD (and the current branch) to the given commit but leaves the staging area and working directory untouched — everything that was in commits after that point becomes staged, uncommitted changes. git reset --mixed <commit> (the default if no flag is given) also moves HEAD, but additionally resets the staging area to match the target commit, so those changes become unstaged-but-present in the working directory. git reset --hard <commit> goes further still: it moves HEAD and resets both the staging area and the working directory to exactly match the target commit, discarding any uncommitted changes and any commits after the target point from the branch.
Cricket analogy: Like reverting the official scorecard to an earlier over but keeping every run scored since as "unofficial, pending confirmation" (soft), versus also clearing the confirmation stamps so those runs sit unconfirmed on the field (mixed), versus wiping both the scorecard and the field record entirely back to that earlier over (hard).
# Undo the last commit but keep its changes staged, ready to re-commit
git reset --soft HEAD~1
# Undo the last commit and unstage its changes, but keep them in the
# working directory (files still show the edits, just not staged)
git reset --mixed HEAD~1 # --mixed is the default; `git reset HEAD~1` is equivalent
# Discard the last commit AND all its changes completely
git reset --hard HEAD~1
# Unstage a single file without touching the working directory or moving HEAD
git reset HEAD -- src/config/settings.py
# Move a branch to point at a specific commit found via `git log`
git reset --hard 4f2a9c1Reset versus checkout versus restore
Because reset touches HEAD, the index, and the working directory in different combinations depending on its mode, modern Git split some of its jobs out into more explicit commands: git restore now handles restoring working-directory files or unstaging index entries without moving the branch pointer at all, and git switch handles changing branches. git reset remains the command for actually moving the branch pointer — undoing commits at the branch level — which restore and switch deliberately do not do.
Cricket analogy: Like a board splitting the old all-purpose team-manager role into a dedicated fitness restorer who only handles player conditioning (restore) and a dedicated squad-rotation officer who only handles swapping the playing group (switch), while the team-manager role itself narrows to just deciding which match result counts as official (reset moving the branch pointer).
A useful mental model: --soft only moves the label (HEAD/branch); --mixed also erases the staging area's memory of the difference; --hard also overwrites the actual files on disk. Each flag reaches one layer further into the three trees Git tracks — commit, index, working directory.
git reset --hard permanently discards uncommitted changes in the working directory with no prompt — there is no undo for changes that were never committed. Before running it, double-check with git status and git diff, or stash first with git stash if there's any chance you'll want the changes back.
- git reset moves the current branch's HEAD pointer to a given commit.
- --soft leaves the index and working directory untouched — prior changes become staged.
- --mixed (the default) also resets the index — prior changes become unstaged but present in the working directory.
- --hard also overwrites the working directory, discarding uncommitted changes permanently.
- git restore and git switch now cover some jobs reset used to do, leaving reset focused on moving the branch pointer.
- Reset rewrites history on the current branch — avoid it on commits already pushed and shared with others.
Practice what you learned
1. Which git reset mode leaves both the staging area and the working directory unchanged, only moving HEAD?
2. What is the default mode of `git reset` when no flag is specified?
3. Why is `git reset --hard` considered particularly dangerous?
4. Which modern command is preferred for unstaging a file without moving the branch pointer at all?
5. What happens to a branch's commit history when `git reset --hard HEAD~2` is run?
Was this page helpful?
You May Also Like
git revert vs git reset
Two different ways to undo changes in Git — revert creates a new commit that inverses a prior one, while reset moves the branch pointer and rewrites history — and when to use each safely.
Recovering Lost Commits with reflog
Discover how git's reflog silently tracks every movement of HEAD and branch tips, giving you a safety net to recover commits after resets, rebases, or accidental deletions.
The Staging Area
Understanding Git's staging area (index) as the intermediate step between editing files and committing them, and why it gives you fine-grained commit control.
Amending and Rewriting Commits
Amending lets you fix the most recent commit's message or contents without creating a new commit, while broader history rewriting tools reshape older commits before sharing them.
Related Reading
Related Study Notes in Software Engineering
Browse all study notesMicroservices Study Notes
Software Architecture · 30 topics
Software EngineeringTesting & TDD Study Notes
Software Testing · 30 topics
Software EngineeringDesign Patterns Study Notes
Software Design · 30 topics
Software EngineeringSoftware Engineering Study Notes
Python · 40 topics
Software EngineeringSystem Design Study Notes
Architecture · 40 topics