How Does Git Reset Work?

Want to know how the Git reset option works?

In a series of Git courses on Envato Tuts+, I went through some of the fundamental concepts of Git in simple videos.

In this video from the series, you’ll learn all about Git reset. You’ll see how to use each kind of reset and how these varieties interact with the three Git trees:

  • soft: only changes HEAD, but doesn’t change staged files in index or working files.
  • mixed: moves HEAD and updates the index with the contents of the revision to which HEAD now points.
  • hard: moves HEAD and updates the index and working directory—this is the only version of reset that can cause data loss.

I’ll also show you how to use git reset on individual files.

Git Basics: Reset


How Git Reset Works

Git reset. What does it do? It's how you undo some changes that are local to your computer. When you have done some work that you need to rewind, reset is your friend. You can just start over. You can jump back and forth between the contents of various commits and do a bit of time traveling.

Git reset time travelling illustration

You have a few options at your disposal with git reset. You can go hard, soft, and mixed, and you can also operate and hold commit objects or do it at an individual file level. 

Each of these three variations affect specific trees which git uses to handle your files and their contents.

How Git Reset Affects the Three Trees

Metaphorically speaking, every reset option changes a different tree, a different part of how git saves snapshots. 

Trees, what are we talking about here? Git uses the working directory, the index (also known as the staging area), and something called HEAD for creating and for retrieving commits. 

Git three trees

The working directory lets you change files that you can stage into the index. This staging area lets you fine tune and select what you want to put into your next commit. A commit object is a cryptographically hashed version of your contents. It has some added metadata and points back to previous commits which lets us do our time traveling bits. 

HEAD is a reference that points to such commit objects. It is merely a pointer that updates with every new commit or change of branch. You can move it around and target any point in time with the commit object. 

For more info about trees and such, have a look at my video about the three trees and Git. It covers the basic workflow in Git and is a solid basis to better understand the logic of using git reset.

The Different Reset Options Explained

Now let's look at the different options.

Git reset --hard

This goes the whole nine yards. It will first move HEAD and update the index with the contents of the commit HEAD is now pointing at. Then it will update the working directory with the contents of the index, thereby possibly destroying content you changed in the working directory.

Git reset hard

Therefore, it is the only version of git reset that is a bit dangerous if you don't know what you are doing. 

Git reset --mixed

This will move HEAD and also update the index with the contents of the desired commit that HEAD is not pointing at. The working directory is unaffected by that operation.

Git reset mixed

The mixed option is the default if you don't provide git reset with an option. It is always working directory safe, so no need to be afraid to lose your work. 

Git reset ---soft

This option will only move HEAD and stops right there. In effect, this will undo the last git commit command.

Git reset soft

The working directory and files that might be staged are still unaffected by that operation. 

Using a File Path

With all these options for git reset, you specifically tell git where to stop replaying, rewinding the contents and files from previous commits to specify the trees you want to affect. We can take this a step further and program reset with a file path.

If you use a path, Git won't move HEAD. Why? Because HEAD points to a commit object, and it cannot point to only a subset of that. In other words, HEAD does not point to specific files but to commit objects, which consist of block files and some metadata. The index and working directory, on the other hand, can be addressed in slices of sorts.

Only the index and working directory play a role when you use a path. It simply copies the contents of a file into the index, and it cannot do much else. git reset some-file.ext assumes that by default you meant git reset --mixed HEAD some-file.ext and won't affect the working directory.

By the way, because HEAD cannot move, the soft option would be pointless. Let's say you've been working on version 3 of a file and added it to the index for your next comment. Now you want to unstage these changes. Run git reset some-file.ext to unstage that particular file.

Git reset with a file name

As a result, the index will be populated by the state of your file from version 2, the version from your last commit the commit HEAD is pointing at. The changes you made in your file, version 3 basically, are still available in the working directory. You're still able to get at these changes to stage version 3 of this file.

Git reset with a file stage 2

So what you do in effect with git reset some-file.ext is you only manipulate the index. 

Reset vs. Checkout

What about git reset --hard some-file.ext? Why can't we use that as well? 

This functionality is accomplished by git checkout with a filename. git checkout some-file.ext is actually what git reset --hard some-file.ext would do, but Git does not let us use the hard option.

Let's take this another step further. We can target any commit to reset a specific file, not just the most recent one represented by HEAD. This resets the targeted files in the index to the state of a certain commit, again without affecting the working directory or any commit.

After you've reset the index to the state of a certain commit, a backwards update of sorts, you can use git checkout with a filename to check out the contents of the index into your working directory. 

Git checkout

Why use checkout? Because git reset --hard with a file is not something Git lets you do.

But be careful. Using git checkout with a file path will get rid of your newest changes in your working directory and replace it with the version of the file in that specific commit.

Watch More Git Courses

If you found this useful, why not check out some more Git courses?

You could watch our Introduction to Git and GitHub or try the other Coffee Break Courses in this series:



Related Articles