Q16 of 40 · Git

Explain the three modes of `git reset` — `--soft`, `--mixed`, and `--hard` — with concrete use cases for each.

GitMidgitresetsoftmixedhardstaging

Short answer

Short answer: `--soft` moves HEAD only (staged diff preserved), `--mixed` moves HEAD + clears the index (changes land unstaged), `--hard` moves HEAD + clears index + discards working tree. Use `--soft` to squash, `--mixed` to edit, `--hard` to abandon.

Detail

All three modes move the branch pointer (HEAD) to the target commit. What differs is how aggressively they reset the index (staging area) and working tree.

--soft: Only HEAD moves. The index and working tree are untouched, so all the changes from the discarded commits reappear as staged changes ready to commit again. Classic use case: squash the last N messy commits into one clean commit by git reset --soft HEAD~N followed by git commit -m "clean message".

--mixed (default): HEAD moves and the index is cleared, but the working tree keeps all changes as unstaged modifications. Use this when you want to redo which files are included in the commit, or when you want to inspect/edit changes before re-staging them selectively.

--hard: HEAD moves, index is cleared, and working tree is reset to match the target commit — all uncommitted changes are gone. Use only when you deliberately want to abandon work (e.g., scrapping a failed experiment). Note that even after --hard the dangling commits are still reachable via git reflog for about 30 days unless you run gc, so recovery is usually possible.

// EXAMPLE

# --soft: squash last 3 commits into one
git reset --soft HEAD~3
git commit -m "feat: add login flow (squashed)"

# --mixed: unstage a file you accidentally staged with 'git add .'
git reset HEAD -- config/secrets.yml   # same as: git restore --staged

# --hard: throw away all uncommitted work and return to last commit
git reset --hard HEAD

# --hard to a specific commit (dangerous on shared branches)
git reset --hard a1b2c3d4

# Recover after accidental --hard (commits visible in reflog for ~30 days)
git reflog
git reset --hard HEAD@{2}

// WHAT INTERVIEWERS LOOK FOR

Clear distinction between all three modes, not just soft vs hard. Practical use cases (squash with --soft, selective re-stage with --mixed). Mentioning reflog as a recovery path after --hard.

// COMMON PITFALL

Confusing `git reset HEAD -- <file>` (unstage a file) with `git checkout HEAD -- <file>` (discard working tree changes). The modern equivalents are `git restore --staged <file>` and `git restore <file>` respectively.