How to remove a commit that has already been pushed?

You just ran git push, sending your changes to your remote server, now you realize there’s a problem with one of those commits. You’d like to undo that commit.

A git reset could work, but it would also remove the commit from the history of the remote server. By force pushing the new history, you could potentially lose the work of your coworkers if they have already pulled from the remote server.

A git revert is a safer alternative as it creates a new commit that undoes the changes made in the commit you want to remove. This way, you can push the new commit to the remote server without losing any history.

Setup

Let’s add three commits to your repository.

We’ll start with a clean repository:

alina

alina git:( main ) git status

On branch main

Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

alina git:( main )

And now we’ll add one commit:

alina

alina git:( main ) echo "add line 1" >> README.md

alina git:( main ) git add README.md

alina git:( main ) git commit -m 'add line 1'

[main d8aa742] add line 1

 1 file changed, 2 insertions(+), 1 deletion(-)

alina git:( main )

This gives us the following commit graph:

alina

d8aa7424dc6afcmainHEAD

And we’ll repeat that process with two other commits (we’ll omit the terminal output and commit graph for brevity).

Eventually, we’ll have the following commit graph:

alina

4282fc81b0ef4ad8aa7424dc6afcmainHEAD

And the content of the README.md file will be:

alina

alina git:( main ) cat README.md

# arenas

GitPowerUp Repository: arenas

add line 1

add line 2

add line 3

alina git:( main )

Let’s suppose that at this stage, you push your commits to the remote server:

alina

alina git:( main ) git push

Enumerating objects: 11, done.

Counting objects: 100% (11/11), done.

Delta compression using up to 8 threads

Compressing objects: 100% (6/6), done.

Writing objects: 100% (9/9), 688 bytes | 688.00 KiB/s, done.

Total 9 (delta 2), reused 0 (delta 0), pack-reused 0

remote: . Processing 1 references

remote: Processed 1 references in total

To ssh://remote.mygit.com/gitpowerup/arenas.git

   4dc6afc..4282fc8  main -> main

alina git:( main )

The commit graph will show that your commits landed on the remote server:

alina

4282fc81b0ef4ad8aa7424dc6afcmainorigin/mainHEAD

Now it would be frowned upon if you were to rewrite the history of the remote server, so you need to find a way to undo the commit without rewriting history.

Solution

Let’s take a look at your list of commits:

alina

alina git:( main ) git log --oneline

4282fc8 (HEAD -> main, origin/main, origin/HEAD) add line 3

1b0ef4a add line 2

d8aa742 add line 1

4dc6afc Initial commit

alina git:( main )

The git revert command will create a new commit that undoes the changes made in the commit you want to remove.

If you want to revert the last commit, you can use the HEAD reference (or the commit hash) as the argument for the git revert command:

alina

alina git:( main ) git revert HEAD

... opens the associated editor for you to comment ...

alina git:( main )

This command will add a new commit to your history that reverts the changes made in the last commit:

alina

b7815864282fc81b0ef4ad8aa7424dc6afcmainorigin/mainHEAD

And your README.md file will be back to its previous state:

alina

alina git:( main ) cat README.md

# arenas

GitPowerUp Repository: arenas

add line 1

add line 2

alina git:( main )

If you want to remove the add line 2 commit as well, you can use git revert again, this time using the SHA of the commit that added that line:

alina

alina git:( main ) git revert 1b0ef4a

... editor opens up ...

alina git:( main )

Here is your updated README.md file:

alina

alina git:( main ) cat README.md

# arenas

GitPowerUp Repository: arenas

add line 1

alina git:( main )

And finally, you can revert the addition of the first line:

alina

alina git:( main ) git revert d8aa742

... editor opens us

alina git:( main )

The commit graph shows that all these reverts have added new commits on top of the existing ones:

alina

b009973b78de7ab7815864282fc81b0ef4ad8aa7424dc6afcmainorigin/mainHEAD

And the README.md file is back to its original pristine state:

alina

alina git:( main ) cat README.md

# arenas

GitPowerUp Repository: arenas%                                                                                                    

alina git:( main )

This time, it is safe to push as there is no history rewriting involved:

alina

alina git:( main ) git push

Enumerating objects: 11, done.

Counting objects: 100% (11/11), done.

Delta compression using up to 8 threads

Compressing objects: 100% (5/5), done.

Writing objects: 100% (9/9), 832 bytes | 832.00 KiB/s, done.

Total 9 (delta 2), reused 2 (delta 0), pack-reused 0

remote: . Processing 1 references

remote: Processed 1 references in total

To ssh://remote.mygit.com/gitpowerup/arenas.git

   4282fc8..b009973  main -> main

alina git:( main )

The only side effect is that the git history is a bit messy, but that is a small price to pay for pushing to the remote too fast.