How 'git reset' isn't as scary as it looks.
Tags: git
Published: 2022-07-26 15:32:31

For me `git reset` did look scary initially when I was first learning Git. But now that I have a better understanding after using the command more often and looking at the git history to understand what happened. At first glance this could be very daunting but it gets less daunting after you get a bit more comfortable with what is going on.

Before we get started, I want to mention my blog post is intended to help get you get comfortable with the `git reset` command if you are a beginner with using Git. If you are already a seasoned Git user, then I would still appreciate your input and thoughts. Join the conversation and teach me something I don't know about reset! I challenge you to do so! Let's get started!

Here are a few things you should understand before diving in:
- Committed versus Uncommitted code
- Staged versus Unstaged code

### So what is the reset command?
It is essentially your undo button in the Git world. Your CMD+Z for MacOS. Your Ctrl+Z for Windows. Etc. Granted though, in Git you could always just undo your code changes and then create a new commit over the latest commit. You are basically doing the same thing but you have to take an extra step in changing the code manually. Doing it manually is easy when there are only a few lines of code but when you are dealing with 100+ lines that have been changed, you can save time with using `git reset`. (Plus you will feel amazing running this command) Now why should we use `git reset`?

#### Here are two reasons why we would even care about 'reset':

- When you have committed lots of WIP (Work in progress) work that needs to be cleaned up from your commit history on your local feature branch
- When you have made a mistake somewhere in code (50+ lines of breaking changes) and you really need to hit the undo button quick (trust me happens to the best of us we are all human after all)

When you are executing the 'reset' command you are modifying commit history. What happens is the commit(s) that you reset will be gone. This means that 'git reset' puts the changes back into staging/unstaging. The previous commit(s) are removed and you are now free to move changes you want to keep into a new commit and throw out changes you don't want.

This is a great tool if you are working individually on your own branch but `git reset` will have huge impacts on your feature branch if you are working with another dev on the same one. This is because you are modifying existing history and removing that history from existence. 

#### Example on why this can be dangerous
Say for example, another dev has pulled your changes down to help you with the feature/fix before the reset. You then find some code changes that you want to reset. You then run the 'git reset' command to undo those changes. The result is your local vs remote branch HEAD commits differ. Git will tell you that you need to force push your changes when you try to push these changes to the remote branch. You then proceed to do that and the results there now are that the remote branch has your 'undo' changes while your dev partner has the old changes. If he tries to 'git pull' your branch it will cause errors when merging due to the fact that the HEAD commits between the remote branch and his are different. They have commits in their branch which are non-existent anymore. This causes headaches and requires the other dev to completely delete their branch and pull your branch down again.

#### Here is an example showing some Git history before and after a `git reset` command is executed.



![before-reset](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qv9cgtkaxaqbd791bwb.png)
> In the image above, I created a repository with two commits just adding 2 files to the project (file a and b)

![reset-done](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8knop5fs5mlkdhge4e1.png)
> The command above shows that I chose to reset to the hash starting with 'bf59e' meaning I want to undo the changes which were made in commit hash '7d313'. If there happens to be another commit after 'bf59e' (say 'abcede') and I had decided to reset to that one instead, I would have ended up undoing the changes in both '7d313' and 'bf59e'. 'git reset' will basically reset everything between the HEAD (your current latest commit) to the one which was chosen.

![after-reset](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uigg5c02xs0oa5ph5kcs.png)
> This image above is the result of the reset done in the previous image.

![reset-take-action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdpsbhk4vtpqbtd73pu2.png)
> This image above shows the changes that have been reset. The original commit added the file. Now the file is back in my untracked unstaged changes and is ready to be modified for recommitting. You can then add back in the changes you want to go through and leave out the unwanted changes. My example only has one change but imagine having 20+ changes which you are trying to reset. Modifying the changes manually can take a lot of time.

### What about 'git revert'?
A similar command is 'git revert'. This is the safer of the two commands you can do if you are unsure but are trying to undo some of the changes you made. No matter where you are in your codebase this command will create a new commit on top of your existing ones with the undo changes. Whether you are in your main/dev branch or your feature branch you will always see a new commit after this command is executed with a message indicating there was a "Revert". All you need to provide is the commit hash that you want to revert. This command is safe to be used in any branch whether you are the only one working on it or your team is also working on that same branch together. The 'git revert' command has no impact on anyone working on the branch as a new commit is created on top of the existing ones. The commit history goes forward rather than backwards. (not removing any git commit history while still undoing code changes)

#### A reason to be using revert would be:

- When you have released a feature too early and need to rollback (the feature has already been merged in with the rest of your codebase main/dev branch)
- The same reasons mentioned with using 'git reset' could also be applied here.

#### Here is an example showing some Git history before and after a 'revert' command is executed.

![before-revert](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xoso5e3ydj688rrpb9an.png)
> The above image is showing the same repository as in the 'reset' example.

![revert-message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1do3nwavxcanegwt4k3s.png)
> This image above shows the message that you see after running the command to revert.

![revert-done](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f37vlwngogp5jdhl1rv6.png)
> In the image above the revert is complete. Notice I chose to revert commit '7d313'. With 'revert' we choose the commit hash that we want to undo (different from reset). In the end we are still undoing the same changes but we select a different commit hash when we execute the command.

![after-revert](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l46ecgbvg5f66stpr2x9.png)
> From the image above we got the results and we see an extra brand new commit. The message for the commit indicates that a 'revert' has happened with the commit hash which was selected.

---

In conclusion, 'git revert' is undo with history and 'git reset' is undo without history. Both are very great tools to use when trying to undo mistakes we have made. This just scratches the surface of these two commands there are still more complex things you can do with them. There are many options you can add to them that will enhance what they do. Those I am still exploring and if you are interested in reading more let me know!

TLDR: 'git revert' moves you forward in git history; 'git reset' moves you back in git history. They are both great useful tools for undo-ing any mistakes.

Thanks for reading! Have a great day!


Cover image credit: https://unsplash.com/photos/TgQUt4fz9s8