How to undo git commits? Locally & Remotely.
Tags: git, beginners, tutorial, webdev
Published: 2022-06-26 20:38:00

TL:DR ⏩

1. In the repo, open a new terminal window 
2. Enter this command: 
`git log --oneline --decorate --graph`
3. Find the commit hash you want to revert the repo to.
4. Enter this command: 
`git reset --hard theHashOfTheCommitHere`

Example: `git reset --hard 0ffbffgs3`
5. Then enter: 
`git clean -f -d`
6. Finely you need to force push the reset repo to the remote with this command: 
`git push -f`

To exit git at any time you and type `q` next to the colon at the bottom of your CLI.

In summary:

> `git log --oneline --decorate --graph`
> `git reset --hard xxxxx`
> `git clean -f -d`
> `git push -f`

&nbsp;
&nbsp;



Long version. ⬇️

At some point, you'll be commit something to a repo that you look back and wish you didn't commit that feature/bug fix/OnlyFans video.

So when that happens and you have even pushed the commit to remote, what should you do?

## How do you undo git commits? 
## Locally & remotely.

&nbsp;
&nbsp;



## Step #1: `git log --oneline --decorate --graph`
&nbsp;
&nbsp;


You need to explore your git repo and the status of it. This is so we can find the hash number for the commit you want to revert back too. 

You need to open the repo in your terminal/command line interface (CLI) inside of your working repo directory and **in the branch you want to reset the commit on**. You can enter this command:

&nbsp;
### `git log --oneline --decorate --graph`
&nbsp;

This will output/display this in your terminal:

![git log in oneline, decorate, graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yh7qz1tqb37woawcnekv.png)

Let's break this command down to better understand it.

To exit git at any time you can type `q` next to the colon at the bottom of your CLI.

&nbsp;
⭕ 
If you don't need to know the break down of the command, go to: &nbsp;
 **Step #2: `git reset --hard xxxxx`** 
⭕
&nbsp;


### `git log`
&nbsp;


This part simply gives you a record or log of all the commits you have created in this repo. However unlike the above screen shot which lists them all on one line.

This gives you very detailed description of your git commits.

![Detailed description of your git commits](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uc19uydoel52at8tkvu3.png)

### `git log --oneline`
&nbsp;

This is the **first flag** in the command and is used to format the output of the log. if you do not use this the output log would look like this:

No `--oneline`
&nbsp;

![Detailed description of your git commits](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uc19uydoel52at8tkvu3.png)

With `--oneline`
&nbsp;

![git log in oneline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m829c4aeehjstu49v5ab.png)

Git Documentation says:
[This is a shorthand for "--pretty=oneline --abbrev-commit" used together.](https://www.git-scm.com/docs/git-log#Documentation/git-log.txt---oneline)

### `git log --oneline --decorate`
&nbsp;

The second flag in the command is another formatting flag, that will highlight what [Git Reference](https://git-scm.com/book/en/v2/Git-Internals-Git-References) you are on and there are some options you can added to the end of `--decorate` such as `--decorate[=short|full|auto|no]`

Git references are bit out of the scope for this tutorial, however if you are aware of them, you may find this part a useful flag.

Here is a small demo of the command.

`git log --oneline --decorate=short`
&nbsp;

![Output of git log --oneline --decorate=short](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rrilrrb3hexc6ia1fh67.png)

`git log --oneline --decorate=full`
&nbsp;

![Output of git log --oneline --decorate=full](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3r16vel52vh4thu5lqc.png)

[--decorate[=short|full|auto|no]
Print out the ref names of any commits that are shown.](https://www.git-scm.com/docs/git-log#Documentation/git-log.txt---decorateshortfullautono)


## `git log --oneline --decorate --graph`
&nbsp;

`--graph` is the third and last flag in the command. It is a non essential flag, but will allow for a bit of a nice formatting so you can visualize your git log better.

Specifically it will deal with commits you have merged from other branches and show that merge in a graphical text based visualization.


No `--graph`
&nbsp;

![Output of git log --oneline --decorate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/saoxod41ic1tpzf32wdf.png)

With `--graph`
&nbsp;

![Output of git log --oneline --decorate --graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63jeh8ohyjliy35e5wkn.png)

And that is what, `git log --oneline --decorate --graph` does.

&nbsp;
&nbsp;

### Step #2: `git reset --hard xxxxx`

&nbsp;
&nbsp;


Now you have the commit hash you need and now it is time to reset your working git branch to the commit you want to revert back too.


To do this, you need to do use the command:

`git reset --hard xxxxx`
&nbsp;

> --hard
> Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded. Any untracked files or directories in the way of writing any tracked files are simply deleted. [Source: git-reset Documentation](https://www.git-scm.com/docs/git-reset#Documentation/git-reset.txt---hard)

What does that mean? Well you have to compare this command to: 

`git reset --soft xxxxx`
&nbsp;

Let's look at the CLI/terminal in VScode in a working repo and compare the two.  

With: `git reset --soft xxxxx`
&nbsp;

![Using git reset --soft ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/22ae9ntl2d35xiz5sqts.png)

When using `--soft` as a mode you will reset the working directory to the requested commit, however all the changes in the commits after the requested commit will undo, and become staged changes in the repo. As seen above.


With: `git reset --hard xxxxx`
&nbsp;

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

The working directory is now completely clear of all commits after the reset to the requested commit, and there is no staged changes, the commits are gone. This is irreversible. 

&nbsp;
**Well kind of irreversible...**
&nbsp;

If you notice at the bottom of the above screenshot you'll see this:

![A screen shot of a pull from orign](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzzx4ajxyyryro4fwsl2.png)

I still have one commit to pull from remote. As you guessed it. It is the one I just reset. At this point your local working directory has been reset, and if that is all you need to do. Then you have finished. But...


![the reset commit added back to repo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/efjplxa418wtvjmnrhl5.png)

...how do you reset a commit when you have already pushed it remotely? 

&nbsp;
&nbsp;

## Step #3: `git clean -f -d`

&nbsp;
&nbsp;


Step back and make sure you have used the command: 
`git reset --hard xxxxx`

After that you can safely move on to the git clean.



https://www.git-scm.com/docs/git-clean

-d

> Normally, when no <path> is specified, git clean will not recurse into untracked directories to avoid removing too much. Specify -d to have it recurse into such directories as well. If any paths are specified, -d is irrelevant; all untracked files matching the specified paths (with exceptions for nested git directories mentioned under --force) will be removed.

-f
--force

> If the Git configuration variable clean.requireForce is not set to false, git clean will refuse to delete files or directories unless given -f or -i. Git will refuse to modify untracked nested git repositories (directories with a .git subdirectory) unless a second -f is given.

These two descriptions of the `-d` & `-f` flag are quite indepth. But to help with a jist what they are doing along with `git clean`.

They will first tell git to clean the working directory of any and all untracked files, using the flag `-d` will say that you have not specified a path and `-f` will tell git "just do it, don't warn me" because once done this can not be un done. 

&nbsp;
&nbsp;
## Step #4: `git push -f`
&nbsp;
&nbsp;

[--force](https://www.git-scm.com/docs/git-push#Documentation/git-push.txt---force)

> ...This flag disables these checks, and can cause the remote repository to lose commits; **use it with care.**

The above description covers the `git push -f` quite well, however it warns us that we should use this command with care and we should, but this is the part where we want git to overwrite the existing commit on the remote repo. **We want to undo a commit remotely.** but to use this command is the final step. once done the commit is undone and you no longer need to do or change anything else. 

 `git push -f`

You have now undone a commit remotely. 

🥳 Congratulations! 🥳

Any questions or queries. Please let me know in the comments. 

Any feedback is appreciated as well!