6. History

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.

What do you do in this case

This is where the git reset command comes in handy. To simulate this scenario, first let's create a new branch called experiment.

Run in Terminal:
git switch -c experiment
Task

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.

Task

Perform all of the above actions.

Awesome! Now, remove the line <!DOCTYPE html> from hello.html, stage, and commit the changes.

Task

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.

Run in Terminal:
git reset main
Task

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.

Hmm... so what HAS changed

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.

We did want to reset everything!

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 .

Task

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.

Run in Terminal:
git status
Task

Check the status of the repository.

The changes in hello.html are gone. But the experiment.html file is still there! Why is that?

Let's see what's going on...

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.

Run in Terminal:
rm experiment.html
Task

Delete the experiment.html file.

Let's check the status of the repository now.

Run in Terminal:
git status
Task

Check the status of the repository.

Great! Our branch is now back to the state it was in when we created it.

Task

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.

Next step
© 2024-2025 GitByBit.All rights reserved.

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.

Learn Git in VS Code