Git Reset

The git reset command is used to undo commits, unstage files, or discard changes. It moves the HEAD pointer (and the current branch pointer) back to a previous commit, effectively "undoing" work.

Important: git reset modifies the commit history. It is primarily meant for undoing changes that have NOT been pushed to a shared remote repository. Using it on public commits can cause problems for collaborators.

The Three Modes of git reset

Git reset has three different levels of "undoing," controlled by flags:

ModeWhat ChangesWorking DirectoryStaging AreaCommits
--softMoves HEAD backUnchangedUnchanged (files remain staged)Removed from history
--mixed (default)Moves HEAD backUnchangedCleared (files become unstaged)Removed from history
--hardMoves HEAD backFiles reverted to that commitClearedRemoved from history

Understanding the Starting State

Commits: A ──── B ──── C ──── D (HEAD)

If git reset HEAD~1 is run, HEAD moves back to C, and the effects on files depend on the mode used.

--soft Reset

Moves HEAD back to the specified commit. The files still exist exactly as they were, AND the changes from the undone commits are still staged.

git reset --soft HEAD~1

Use case: "I committed too early. I want to undo the last commit but keep all changes staged so I can recommit with better changes or a better message."

# Before: Committed a file but want to re-commit with a better message
git log --oneline
# a3f92b1 bad commit message
# b7c3d45 Previous commit

git reset --soft HEAD~1

git log --oneline
# b7c3d45 Previous commit
# (a3f92b1 is gone)

git status
# Changes to be committed:
#   modified: index.html  (still staged!)

git commit -m "Better, descriptive commit message"

--mixed Reset (Default)

Moves HEAD back and clears the staging area. The files are modified in the working directory but need to be re-staged.

git reset HEAD~1
# (same as: git reset --mixed HEAD~1)

Use case: "I committed too early and want to undo the commit, unstage the changes, and decide what to stage and commit again."

git reset HEAD~2
# Moves back 2 commits
# Files are in working directory but NOT staged

--hard Reset

Moves HEAD back and completely discards all changes — both staged and unstaged. The files revert to the state of the target commit.

git reset --hard HEAD~1

Warning: A --hard reset permanently deletes uncommitted changes. This cannot be undone (unless the commit hash is known from git reflog).

Use case: "I made a mess of the last few commits. Throw all of it away and go back to a clean state."

# Completely throw away the last 3 commits and all their changes
git reset --hard HEAD~3

# Go back to a specific commit (all changes after that commit are lost)
git reset --hard a3f92b1

Resetting to the Remote Branch (Discard All Local Changes)

To completely discard all local commits and return to the state of the remote branch:

git reset --hard origin/main

This is useful when local experiments need to be discarded and a fresh start from the remote state is needed.

Unstaging a File with git reset

To remove a file from the staging area (move it back to "modified, not staged") without touching the working directory changes:

git reset HEAD index.html

Or the modern equivalent:

git restore --staged index.html

Recovering from an Accidental --hard Reset

Even after a hard reset, commits can often be recovered using git reflog. The reflog keeps a record of every position HEAD has been at:

git reflog
# a3f92b1 HEAD@{0}: reset: moving to HEAD~3
# b7c3d45 HEAD@{1}: commit: Add feature
# c1d2e3f HEAD@{2}: commit: Update styles

# Recover the lost commit
git reset --hard b7c3d45

git reset vs git revert

Featuregit resetgit revert
Modifies historyYes — removes commitsNo — adds a new commit to undo changes
Safe for shared branchesNoYes
When to useLocal/private branchesShared/public branches

Summary

git reset undoes commits by moving HEAD backward. Use --soft to keep changes staged, --mixed (default) to unstage changes, and --hard to discard changes entirely. Only use reset on local, unpushed commits. For undoing commits that are already on a shared remote branch, use git revert instead.

Leave a Comment

Your email address will not be published. Required fields are marked *