Resetting branches
Sometimes you may want to undo a series of commits and return your branch to a previous state.
Let's say I've been experimenting with some new features on a branch, but after a few commits, I realize that my approach isn't working. I want to scrap all these experimental commits and start over from where the branch originally branched off from main
.
This is where the git reset command comes in handy. To simulate this scenario, first let's create a new branch called experiment
.
git switch -c experiment
Create a new branch called experiment
and switch to it.
Great! Now, let's create a file experiment.html
. Put the string This is an experiment.
inside, stage, and commit the changes.
Perform all of the above actions.
Awesome! Now, remove the line <!DOCTYPE html>
from hello.html
, stage, and commit the changes.
Perform all of the above actions.
Okay, let's say at this point I've sobered up realized that this experiment isn't working out. I want to reset the experiment
branch to the initial state and discard all the experimental commits.
To do this, we can use the git reset
command followed by the reference to the commit we want to reset to. In this case, we want to reset to the commit that the experiment
branch was created from. In other words, this is the latest commit in the main
branch. So instead of specifying a commit hash, we can use the name of the branch we want to reset to: main
.
git reset main
Reset the experiment
branch to the latest commit from main
.
If we check the status of our repository now, we'll see that the experiment.html
file is still there, but it's in the untracked state. This means it's not staged or committed.
If you check hello.html
, you'll also see that <!DOCTYPE html>
is missing. So, the working tree hasn't really changed. It still contains our experimental changes.
What has changed is the branch pointer. It's now pointing to the same commit as the main
branch, effectively discarding all the commits we made on the experiment
branch. This is called a soft reset, meaning that the changes from the discarded commits are still in the working tree.
If we want to keep these changes, we can simply stage and commit them as usual. Sometimes, this is exactly what you want to do. For example, if we wanted to squash a bazillion micro commits into a single meaningful commit, or when we want to split all the changes from one huge commit into multiple sub-commits, etc.
In this case, we want to get rid of all experimental changes, effectively performing a hard reset.
In fact, why don't you discard any changes in the working tree right now? You can use the command that we learned a while back (tip: it starts with the letter r
and rhymes with chore
). If you forgot the necessary command, check the .
Discard the changes in the working tree.
Good job! In fact, we could do the hard reset in a single command by adding the --hard
option to the git reset
command. Running git reset --hard
has saved me a lot of trouble in the past.
Let's check the status of the repository now.
git status
Check the status of the repository.
The changes in hello.html
are gone. But the experiment.html
file is still there! Why is that?
Since this file is untracked, Git doesn't know about it. It's not part of the repository, so it's not affected by the reset command. If we want to completely remove this file, we can simply delete it with the rm command.
rm experiment.html
Delete the experiment.html
file.
Let's check the status of the repository now.
git status
Check the status of the repository.
Great! Our branch is now back to the state it was in when we created it.
Before we proceed, let's switch to the main
branch.
If you want to keep the changes from the discarded commits, you can use git reset --soft
instead of git reset
. This will reset the branch pointer but keep all the changes from the discarded commits in the staging area.
If you want to completely remove all traces of the discarded commits, you can use git reset --hard
. This will reset the branch pointer and discard all changes in the working directory and staging area. Use this with extreme caution!
Be careful when using git reset
, especially with the --hard
option, as it can permanently discard changes. Always double-check that you're resetting to the correct commit, and consider using git stash
to save your uncommitted changes before resetting if you think you might need them later.
The git reset
command is somewhat similar to git restore
, at least naming-wise. Both can be used to undo changes in the working tree. However, git restore
is a newer and somewhat less powerful command: it can only be used to restore files in the working tree, but not move the branch pointer. In fact, this is the reason why this command was introduced: to separate the concerns of moving the branch pointer and restoring files in the working tree. When using git restore
, you are less likely to accidentally break things, as it's more targeted and less destructive than git reset
.
However, for someone who is used to the old git reset
command, it might take some time to get used to the new command. But if you're new to Git, it's a good idea to understand the difference and try to use git restore
instead of git reset
when appropriate.
Hi! I'm Alex, creator of GitByBit.
This page is a part of the interactive course about Git version control.
It's a one-of-a-kind course that is integrated into the VS Code code editor. Learning directly in VS Code lets you operate Git exactly as you would in real life, doing real jobs, writing real code.
In addition, the course has access to your actual terminal, so it can point out mistakes, suggest workarounds, etc.
The course is FREE, there are no Ads or other bullshit. There are optional premium add-ons you can purchase, mainly to support my work (regrettably, I have to eat every day), but that's totally up to you.