Git reset, when and how to use it
Tags: git, tooling, productivity, beginners
Published: 2022-01-19 12:04:03

[Git reset](https://git-scm.com/docs/git-reset) is part of the git commands that used to confuse me, as I did not understand its purpose or use-cases at first.

On top of that, it seemed to be doing very different things depending on its input, which is either a commit or a path.

But once I dug a bit deeper into each option of this command and understood the logic behind it, which eventually is about **undoing staged or committed changes**, it really helped me to manage my commit history or revert my mistakes, which is particularly useful for [my rebase workflow](https://simondosda.github.io/posts/2022-01-03-git-rebase-workflow.html).

With this article, I hope to help you clarify how this command works and how you can use it in your daily development tasks.

## Git reset with a path: unstaging files

When used with a path, the reset command does the opposite of git add: it removes changes from the staging area.

![git reset with a file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/imxeq2tlscsx2wbpe4mf.png)

NB: a new command was recently added to git, `git restore`, to fulfill this purpose and will probably become the advised way to perform this action.
For now, `git restore` is still experimental. Still, I think it should be preferred over `git reset` for unstaging changes, as its implementation seems more intuitive, whereas `git reset` should be used to update the branch's head, as we will see after.

But if you want to use the reset command for unstaging files, here are some examples:

```bash
git reset # unstage all changes
git reset file-a file-b # unstage file-a and file-b files
git reset folder-a/ # unstage all changes in the folder folder-a
```

I personally do not use `git reset` for this purpose as I don't deal much with staging my changes. I usually commit everything (I have [set an alias](https://simondosda.github.io/posts/2021-04-13-git-aliases.html) for this purpose that I am always using), and if I need to commit partial changes, I prefer to use my IDE to do so.

## Git reset with a commit: modifying the head of your branch

When used with a commit, `git reset` allows us to change the head of our branch. While doing so, it allows us to extract the changes between our current head and the new one, and put them in our staging area, working directory, or forget them depending on the mode used.

Let's see how the different modes work.

### The soft mode 🪶

The soft mode keeps your current staging area and working tree as it is while moving your head to the specified commit. Changes between your previous head and the new one are added to the staging area.

![git reset in soft mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ph7tc9wpatrrbq54971n.png)

This option provides a great way to rewrite your history in only one commit, instead of using an interactive `rebase` to squash your commits:

```bash
git reset --soft main
git commit -m' feat: an atomic feature'
```

### The mixed mode 🥗

Using git reset with the mixed mode (the default mode) puts all your changes between your previous and current head, including your current staged changes, in the working directory.

![git reset in mixed mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ucr7hpnf9n84ve0u9qpl.png)

This option is handy when you want to rewrite your history in several commits, for instance to create two commits from all the changes you made from your main branch:

```bash
git reset --mixed main
git commit --interactive -m' fix: a correction aside the main feature'
git commit --all -m' feat: the main feature'

```

### The hard mode 🪨

The heavy-handed one! 
It sets the index to the given commit and removes all changes between your previous and current index or in your working directory.

![git reset in hard mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xtqurytrebyn68po5c0s.png)

This option is perfect if you want to get rid of your current changes:

```bash
git reset --hard HEAD # or just git reset --hard
```

NB: use this command only if you know you are not interested in keeping your current changes, as you will not be able to recover them. 
If you are unsure yet but want to start back from your last commit, use `git stash` instead to put your current changes aside.

Another interesting use-case is to reset your branch to the state of the remote one ([a kind of force pull](https://simondosda.github.io/posts/2022-01-05-git-force-pull.html)):

```bash
git reset --hard origin/my-branch
```

You need to be cautious when using this command as you might lose changes. 
If you made a mistake, it is [still possible to get your lost commits back](https://simondosda.github.io/posts/2022-01-06-git-lost-commits.html), but not your current staged and unstaged changes. 

### The keep mode ✊

This mode is a bit peculiar. It is similar to the hard mode as it will drop the commits between your previous and new head. But it will carry on your unstaged changes and abort if there is any conflict between these changes and the removed commits.

![git reset in keep mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xznu6wt03hgw7dbv5v9l.png)

This command is dedicated to doing one thing: remove commits while being safe that they won't conflict with our current unstaged changes. I don't really find myself in this kind of situation, but if that happens, I guess it is valuable to know this option.

### What about the merge mode?

As explained in the documentation, `reset --merge` is meant to be used when resetting out of a conflicted merge.
This is a particular situation, and as I don't use `merge` in [my workflow](https://simondosda.github.io/posts/2022-01-03-git-rebase-workflow.html), I have never had the use for this command.

But do not hesitate to [read the documentation](https://git-scm.com/docs/git-reset) if you think you might be interested.