Skip to content
Latchkey

git reset --soft/--mixed/--hard: The Three Modes

git reset moves the branch tip; --soft keeps the index and working tree, --mixed (default) resets the index but keeps the working tree, and --hard discards both.

The single most consequential difference in git reset is the mode, because --hard throws away uncommitted work. This page lays out exactly what each mode touches so a CI cleanup step does not delete more than intended.

What it does

git reset <commit> repoints the current branch to <commit>. --soft stops there, leaving your changes staged. --mixed also resets the index to match (changes become unstaged). --hard additionally overwrites the working tree to match the commit, discarding all uncommitted changes.

Common usage

Terminal
# undo last commit, keep changes staged
git reset --soft HEAD~1
# unstage everything but keep edits
git reset --mixed HEAD     # or just: git reset
# discard all local changes and match origin/main exactly
git reset --hard origin/main

Options

ModeMoves branchResets indexResets working tree
--softyesnono
--mixed (default)yesyesno
--hardyesyesyes
--keepyesyeskeeps local edits, aborts if they conflict
--mergeyesyeskeeps unmerged changes, resets the rest

In CI

git reset --hard origin/<branch> is the standard way to force a runner workspace to an exact state, but it silently destroys uncommitted artifacts; pair it with git clean to remove untracked files too. After --hard, the prior commits are still recoverable from the reflog (on a non-fresh clone) until gc runs.

Common errors in CI

"fatal: ambiguous argument 'origin/main'" means the ref was not fetched (shallow or missing remote-tracking ref). "error: Entry '<file>' not uptodate. Cannot merge." appears with --keep/--merge when local edits conflict. On a detached HEAD, reset moves HEAD itself, not a branch, which can surprise scripts expecting a branch to move.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →