Different basic ways to undo commits on git
Tags: git, productivity
Published: 2020-03-18 23:38:25

Git is undoubtedly one of the best version control tools today. However, some features provided by it still are confusing for beginners, especially when it comes to manipulations of the directory tree and the various "status" of files in it. So, I thought about making this post talking about different ways to undoing changes in a git repository in accordance with the situation.

## The "Three Trees" concept

First of all, it is necessary to understand one of the basic concepts of git called "Three Trees". Basically, the directory tree of a git repository has three states, 1) the __working directory__ which is the current file system you are interacting with directly, 2) the __staging area__ which are the files that were selected for the next commit and 3) the __history of commits__ which is the file system saved in the repository through snapshots.

This is a base concept for understanding git. For a more detailed explanation, I suggest this [Bitbucket tutorial](https://www.atlassian.com/git/tutorials/undoing-changes/git-reset).

## When I need to revert changes?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/efkyeghtxcers0b1njsp.jpg)

Commonly we are faced with situations where we want to reverse changes committed in the project, and these situations can be quite varied. To know what command is more appropriated to undo the changes which you desire, it is important to know well your reason for you want to undo these changes on the project. Come discuss some possibilities.

1. Your more recent modification has caused an error or a regression of the project, so you need to only undo the recent changes discarding it.
2. You found a better way to solve a problem and want to redo something keeping this moment on commit history.
3. You committed several files, and you want to undo this commit and do a commit with fewer files.
4. Your commit made a snapshot of changes in a set of files, but you want to restore the content of a specific file no removing the commit.

## Commands to undo changes

There are several ways to undo changes/commits with git. I tried to consider the most basic methods to make the post accessible to all levels of git users. With three simple commands, it is possible to make the most diverse manipulations in the __"Three Trees"__ of git, these are: `git checkout`, `git reset` and `git revert`.

Think on the commits as steps of a ladder, where you can take steps forward and steps backward. Some commands allow you to manipulate the `HEAD` (the pointer that set the current structure of directory) to "walk" through the commits, undoing changes on the directory and letting you made new changes from past commits by overwriting the recent commits.

`git checkout`:
This command is used to change the `HEAD` reference. It is very used to switch for another branch, but also may be used to move the `HEAD` to another commit in the same branch.
Using `git checkout [commit-hash]`, the `HEAD` is pointed to the commit specified by hash. This command also may be used to undo changes not stagged in one specific file using `git checkout -- <file>`.

`git reset`:
Using this command is possible made the directory "forget" all changes of the specific commits (using the `--hard` flag) or keep the modifications made by the commits on the _staged area_ (using the `--soft` flag). The main difference between `git reset` and `git checkout` commands are the `checkout` move only the `HEAD` ref, while the `reset` allows moving all working tree - inclusive the current branch - to the specified commit, breaking the commit history continuity.

A simple example of usage is setting the number of commits for jump backward. Using `git reset [commit-hash] HEAD~4`, the state of the working directory is changed to 4 commits backward from the actual (Pointed by HEAD).

`git revert`:
Using this command, you reverse the changes of the last commit and create a new commit to save this reversion. So, you will keep the reversed commit in the history of your project.

## Applying on the different situations

Knowing these commands and their basic operation, we will look for the most appropriate method of undoing changes for each of the situations mentioned above.

> Your more recent modification has caused an error or a regression of the project, so you need to only undo the recent changes discarding it.

In this case, I use:
```
$ git reset --hard <commit-hash>
```
The `--hard` flag reverses all changes directly on the working directory, thus the modifications are forgotten immediately.
OBS: This command with the `--hard` flag is considered _dangerous_ because you can't recovery your modifications.

> You found a better way to solve a problem and want to redo something keeping this moment on commit history.

In this case, I use:
```
$ git revert <commit-hash>
```
After this command a new commit is created on the commit history, allow to identify where the changes were reversed and if I want to recovery these changes, I have them in the commit history.

> You committed several files, and you want to undo this commit and do a commit with fewer files. 

This is interesting for reorganizing the next commits separating the files in several commits. In this case, I use:
```
$ git reset --soft HEAD~2
```
After this command, the state of the working directory such as the current branch is changed to two steps backward, the current state (step 1) and state of the last commit (step 2), setting the state to one commit before the last commit keeping the more recent changes in the working directory (because the `--soft` flag) allowing to commit it as I desire.

> You made a commit that made a snapshot of changes in a set of files, but you want to restore the content of a specific file no removing the commit.

In this case, I use:
```
$ git checkout <commit-hash> <file>
```
After this command, the file `<file>` will be reversed to its state in the commit `<commit-hash>` and will be staged for the next commit automatically

## Remarks

It is very important to know the situation that led to the need to undo something. Here, simple examples have been shown. 
I believe that looking for simple solutions to recurring problems is a good starting point for starting studies of any technology, and with git, it is no different.

However, there are always more complete and complex ways to work. For an in-depth look at git, I recommend the official git documentation and Atlassian tutorials.

I hope this post can answer someone's doubts.
Thanks for reading ;)

## References used

[Git Docs](https://git-scm.com/docs)
[Git Book](https://git-scm.com/book/en/v2)
[Atlassian Tutorials - Git reset](https://www.atlassian.com/git/tutorials/undoing-changes/git-reset)