reset is a useful command in Git. Basically, it has three options:

  • hard
  • soft
  • mixed(default)

In all the three cases, reset will reset the HEAD pointer(see below) to what you designate.

To illustrate the difference, first you should know how files are kept and referenced in Git. There are three stages:

  • working tree
  • index
  • commit

Initially, all files are in the working tree. When you run

git add

They’ll be indexed(formally called staged), i.e., they’re now in the index. And when you finally run

git commit

They’ll be in the commit.

Besides this, you should also know the HEAD pointer. The HEAD pointer always points to the current commit.

Now we can tell the difference between the hard/soft/mixed options of git reset.

  • --hard will reset both the working tree and the index. In this way, after this is executed, your working tree and index will be exactly what they are for the commit you reset to. And the diff of the current HEAD and the commit you reset to is discarded.

In this way, you have both a clean working tree and a clean index.

  • --soft will keep both the working tree and the index. In this way, after this is executed, your current working tree and index will be kept. And the diff of the current HEAD and the commit you reset to will be added to the index.

In this way, you may have neither a clean working tree nor a clean index.

  • --mixed will keep the working tree but reset the index. In this way, after this is executed, your current working tree will be kept. And what was originally in the index will be reset(However, it still exists in the working tree. This operation is formally called unstage). And the diff of the current HEAD and the commit you reset to will be added to the working tree.

In this way, you have a clean index but may not have a clean working tree.

Since this is the default, you don’t have to explicitly add the --mixed.