Skip to content

git reset — Rewinding History

git reset moves the branch pointer to an earlier commit, effectively removing commits from the tip of the current branch. It is a history-rewriting operation — the commits you reset past become unreachable — so it is only appropriate for local commits that have not been shared.

Used correctly, git reset is one of the most useful tools in Git. Used on pushed commits, it causes serious problems for collaborators.

When you run git reset <commit>, Git moves the current branch pointer (HEAD) to the specified commit. Commits that were ahead of that point are no longer reachable through the branch.

The three modes control what happens to the changes from those removed commits:

ModeBranch pointerStaging areaWorking tree
--softMoved backKeeps changes stagedUnchanged
--mixed (default)Moved backClears staged changesUnchanged
--hardMoved backClears staged changesDiscards changes
Terminal window
git reset --soft HEAD~1

Moves the branch pointer back one commit. The changes from that commit remain staged. Your files are unchanged. Effectively “uncommits” the last commit — putting everything back in the staging area as if you had staged it but not yet committed.

Use case: you committed too early and want to add more to the commit, or you want to rewrite the commit message more thoroughly.

—mixed: uncommit and unstage (the default)

Section titled “—mixed: uncommit and unstage (the default)”
Terminal window
git reset HEAD~1
# or explicitly:
git reset --mixed HEAD~1

Moves the branch pointer back one commit. The changes from that commit are removed from the staging area but kept in your working tree as modified (unstaged) files.

Use case: you want to undo the last commit and the staging, but keep all the changes — starting fresh with what to commit and how.

Terminal window
git reset --hard HEAD~1

Moves the branch pointer back one commit. The changes from that commit are removed from the staging area and discarded from the working tree. Destructive — the changes are gone.

Use case: you want to completely discard the last commit and return to a known clean state. The changes from that commit are lost.

Terminal window
git reset --hard a3f8c12

Moves the branch pointer to a3f8c12. All commits after that point are removed from the branch, and with --hard, all their changes are discarded.

If you reset too far and want to go back, the commits still exist in Git’s object store for a while. Find them with:

Terminal window
git reflog

git reflog is a log of everywhere HEAD has pointed. It shows resets, merges, branch switches — all movement. To recover a reset commit:

Terminal window
git reset --hard <hash-from-reflog>

git reflog is your emergency safety net after a --hard reset you immediately regret. It keeps entries for about 90 days.

If you reset past a commit that has already been pushed to a shared remote, your local history and the remote’s history diverge. Pushing requires git push --force, which overwrites the remote’s history and leaves any collaborators who pulled the old commits in a broken state.

The rule: reset is for local-only commits. For shared history, use git revert.

Squash multiple commits into one:

Terminal window
git reset --soft HEAD~3 # uncommit 3 commits, keep all changes staged
git commit -m "Combined commit message"

Undo a staged git add:

Terminal window
git reset HEAD pine-ridge.txt
# equivalent to: git restore --staged pine-ridge.txt

This is the older form of unstaging — git reset HEAD <file> moves the file out of the staging area. git restore --staged is the modern equivalent.

  1. In your git-practice folder, make two commits that you want to undo locally:
Terminal window
echo "Draft note A" >> pine-ridge.txt && git add . && git commit -m "Draft A"
echo "Draft note B" >> pine-ridge.txt && git add . && git commit -m "Draft B"
  1. Undo both commits with --soft and inspect what happened:
Terminal window
git reset --soft HEAD~2
git status

Confirm the changes are staged. The commits are gone from git log, but the content is still in the staging area.

  1. Now try --mixed:
Terminal window
git reset --mixed HEAD~1 # (or just: git reset HEAD~1)
git status

Confirm the changes are in the working tree but not staged.

  1. Finally, try --hard on a single throwaway commit:
Terminal window
echo "throwaway" >> pine-ridge.txt && git add . && git commit -m "Throwaway"
git reset --hard HEAD~1

Open pine-ridge.txt and confirm the throwaway line is gone.

  1. Run git reflog and find the commit that was just reset away.
  • git reset moves the branch pointer to an earlier commit, removing later commits from the branch.
  • --soft: moves pointer, keeps changes staged.
  • --mixed (default): moves pointer, keeps changes in working tree (unstaged).
  • --hard: moves pointer, discards all changes. Destructive.
  • git reflog shows all HEAD movement and is the recovery tool after an accidental hard reset.
  • Never reset commits that have been pushed to a shared repository. Use git revert for shared history.

The next lesson is the Module 04 recap — a consolidated reference for every undo operation, when to use each, and a preview of Module 05 on working with GitHub.