Commit-level reset
On the commit-level, resetting is a way to move the tip of a branch to a different
commit. This can be used to remove commits from the current branch. For example,
the following command moves the hotfix
branch backwards by two commits.
git checkout hotfix
git reset HEAD~2
The two commits that were on the end of hotfix
are now dangling commits, which
means they will be deleted the next time Git performs a garbage collection. In
other words, you’re saying that you want to throw away these commits. This can
be visualized as the following:
This usage of git reset
is a simple way to undo changes that haven’t been
shared with anyone else. It’s your go-to command when you’ve started working on
a feature and find yourself thinking, “Oh crap, what am I doing? I should just
start over.”
In addition to moving the current branch, you can also get git reset
to alter
the staged snapshot and/or the working directory by passing it one of the following
flags:
--soft
– The staged snapshot and working directory are not altered in any way.--mixed
– The staged snapshot is updated to match the specified commit, but the working directory is not affected. This is the default option.--hard
– The staged snapshot and the working directory are both updated to match the specified commit.
It’s easier to think of these modes as defining the scope of a git reset
operation:
These flags are often used with HEAD
as the parameter. For instance,
git reset --mixed HEAD
has the affect of unstaging all changes, but leaves them
in the working directory. On the other hand, if you want to completely throw away
all your uncommitted changes, you would use git reset --hard HEAD
. These are
two of the most common uses of git reset.
Be careful when passing a commit other than HEAD
to git reset
, since this
re-writes the current branch’s history. As discussed in
The Golden Rule of Rebasing,
this a big problem when working on a public branch.