Soft, Mixed, and Hard Reset

Updated

October 30, 2026

Soft, Mixed, and Hard Reset

After this page you can predict git status after --soft, --mixed, and --hard, and you can put the branch name back with ORIG_HEAD.

One commit, three trees

Start from a clean main on ~/desk/desk-api (chapter 3). This page adds one scratch commit, tries each mode, and removes that commit at the end.

cd ~/desk/desk-api
git switch main
git status

Ignored files such as .env are fine. Commit or restore any other uncommitted work before you continue.

echo "scratch" >> README.md
git add README.md
git commit -m "lab: reset modes"
 A ← B ← S     main
 HEAD, index, and worktree all name S

S is the scratch commit. Each mode below starts from S. Git records the old tip in ORIG_HEAD whenever a reset moves the branch, so git reset --hard ORIG_HEAD returns to S.

--soft moves the name

git reset --soft HEAD~1
git status
 HEAD → B
 index still S       "Changes to be committed"
 worktree still S

main now names B. The scratch line is staged. git log no longer shows lab: reset modes. The commit object stays in the reflog (chapter 17).

git reset --hard ORIG_HEAD
git log --oneline -1

You are back on the scratch commit. The line is in README.md, and status is clean.

--mixed moves the name and the index

--mixed is the default. git reset HEAD~1 and git reset --mixed HEAD~1 are the same command.

git reset HEAD~1
git status
git diff

Git prints Unstaged changes after reset:.

 HEAD → B
 index matches B      the scratch line is not staged
 worktree still S     "Changes not staged for commit"

The patch is in the working tree. The next commit includes it only after git add.

git reset --hard ORIG_HEAD

--hard moves all three

git reset --hard HEAD~1
git status
grep scratch README.md || echo "scratch line is gone"
 HEAD, index, and worktree all match B
 tracked files match B

The line is gone from disk. Untracked files are still on disk. --hard rewrites tracked files to the commit you named and leaves untracked and ignored files alone.

git reset --hard ORIG_HEAD

The scratch commit is the branch tip again, and the line is back. ORIG_HEAD is the immediate undo. After other commands have moved HEAD, the reflog is the record (chapter 17). The lab at the end of this chapter recovers with HEAD@{1} on purpose.

Remove the scratch commit

git reset --hard HEAD~1
git status
git log --oneline -5

lab: reset modes is off the log. README.md has no scratch line. The object remains in the reflog until it expires.

Where this is safe

Use these modes on a local branch nobody else has fetched. On a main other people already have, moving the name and pushing is a force-push (chapter 11). A published undo is git revert (chapter 10). The next page is how to choose restore, reset, or revert.