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.