git reset
Move the current branch pointer to a different commit, unstaging files or undoing commits depending on the mode.
You've staged files for commit but realize you want to unstage them, or you've
made commits locally that you want to undo before pushing. git reset moves
your branch pointer and optionally modifies the staging area and working
directory, giving you control over the relationship between these three states
of your repository.
The most common use is unstaging files. After running git add on several
files, you decide one of them shouldn't be in the next commit. Running
git reset filename.js unstages that file while keeping your changes in the
working directory. This is safer than git checkout -- filename.js, which
discards changes entirely.
To unstage everything you've staged, use git reset with no arguments. This is
the inverse of git add .—it clears the staging area while preserving all your
file modifications. Your work isn't lost; it's just not staged anymore.
Reset Modes and Commit Management
When resetting to a specific commit, the mode determines what happens to your working directory and staging area. The three modes are:
git reset --soft abc123 moves your branch pointer to commit abc123 but leaves
your staging area and working directory unchanged. Commits after abc123
disappear from your branch history, but their changes remain staged, ready to
commit again. This is useful for rewriting commit messages or combining several
commits into one.
git reset --mixed abc123 (the default when you don't specify a mode) moves the
branch pointer and unstages changes, but keeps your working directory intact.
Changes from undone commits remain as uncommitted modifications. Use this when
you want to redo commits differently but keep the work.
git reset --hard abc123 moves the branch pointer, clears the staging area, and
resets the working directory to match commit abc123. This discards all changes
after that commit—both committed and uncommitted. It's powerful but dangerous
since it destroys work. Only use hard reset when you're certain you want to
throw away changes.
Common Scenarios
A frequent scenario is undoing the last commit: git reset HEAD~1 moves back
one commit, putting those changes back in your working directory (with
--mixed) or staging area (with --soft). This is less extreme than
git commit --amend because it completely removes the commit rather than
replacing it.
When you've committed to the wrong branch, reset helps fix it. If you
accidentally committed to main instead of a feature branch, you can create the
feature branch, then reset main back before the commit: git checkout main,
git reset --hard HEAD~1, git checkout feature-branch (which has the commit
because you created it after committing).
Pull Request Safety
Never use reset on commits you've already pushed to a shared branch where others might have based work on them. Reset rewrites history by moving the branch pointer, which causes problems for collaborators who have those commits. On your personal feature branches that only you work on, reset is safe and useful for cleaning up before pushing.
If you reset too far or reset --hard by mistake, git reflog shows where your
branch pointer has been, letting you reset back to where you were. The commits
aren't truly deleted immediately—Git keeps them for a while in the reflog,
giving you a chance to recover from mistakes.
Understanding reset means understanding Git's three trees: HEAD (current branch
pointer), index (staging area), and working directory. Reset moves HEAD and
optionally resets the other two to match, giving you precise control over the
state of your repository. The key is choosing the right mode for what you want
to achieve and being extremely careful with --hard.
