896
votes

I have a project in a remote repository, synchronized with a local repository (development) and the server one (prod). I've been making some commited changes already pushed to remote and pulled from the server. Now, I want to undo those changes. So I could just git checkout to the commit before the changes and commit the new changes, but I'm guessing that there will be problems to push them again to remote. Any suggestion on how should I proceed?

13

13 Answers

1070
votes

You can revert individual commits with:

git revert <commit_hash>

This will create a new commit which reverts the changes of the commit you specified. Note that it only reverts that specific commit, and not commits that come after that. If you want to revert a range of commits, you can do it like this:

git revert <oldest_commit_hash>..<latest_commit_hash>

It reverts the commits between and including the specified commits.

To know the hash of the commit(s) you can use git log

Look at the git-revert man page for more information about the git revert command. Also, look at this answer for more information about reverting commits.

479
votes

A solution that keeps no traces of the "undo".

NOTE: don't do this if someone allready pulled your change (I would use this only on my personal repo)

do:

git reset <previous label or sha1>

this will re-checkout all the updates locally (so git status will list all updated files)

then you "do your work" and re-commit your changes (Note: this step is optional)

git commit -am "blabla"

At this moment your local tree differs from the remote

git push -f <remote-name> <branch-name>

will push and force remote to consider this push and remove the previous one (specifying remote-name and branch-name is not mandatory but is recommended to avoid updating all branches with update flag).

!! watch-out some tags may still be pointing removed commit !! how-to-delete-a-remote-tag

304
votes

What I do in these cases is:

  • In the server, move the cursor back to the last known good commit:

    git push -f origin <last_known_good_commit>:<branch_name>
    
  • Locally, do the same:

    git reset --hard <last_known_good_commit>
    #         ^^^^^^
    #         optional
    



See a full example on a branch my_new_branch that I created for this purpose:

$ git branch
my_new_branch

This is the recent history after adding some stuff to myfile.py:

$ git log
commit 80143bcaaca77963a47c211a9cbe664d5448d546
Author: me
Date:   Wed Mar 23 12:48:03 2016 +0100

    Adding new stuff in myfile.py

commit b4zad078237fa48746a4feb6517fa409f6bf238e
Author: me
Date:   Tue Mar 18 12:46:59 2016 +0100

    Initial commit

I want to get rid of the last commit, which was already pushed, so I run:

$ git push -f origin b4zad078237fa48746a4feb6517fa409f6bf238e:my_new_branch
Total 0 (delta 0), reused 0 (delta 0)
To [email protected]:me/myrepo.git
 + 80143bc...b4zad07 b4zad078237fa48746a4feb6517fa409f6bf238e -> my_new_branch (forced update)

Nice! Now I see the file that was changed on that commit (myfile.py) shows in "not staged for commit":

$ git status
On branch my_new_branch
Your branch is up-to-date with 'origin/my_new_branch'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   myfile.py

no changes added to commit (use "git add" and/or "git commit -a")

Since I don't want these changes, I just move the cursor back locally as well:

$ git reset --hard b4zad078237fa48746a4feb6517fa409f6bf238e
HEAD is now at b4zad07 Initial commit

So now HEAD is in the previous commit, both in local and remote:

$ git log
commit b4zad078237fa48746a4feb6517fa409f6bf238e
Author: me
Date:   Tue Mar 18 12:46:59 2016 +0100

    Initial commit
144
votes

This will remove your pushed commits

git reset --hard 'xxxxx'

git clean -f -d

git push -f
94
votes

You can REVERT (or you can also call it DELETE) the Git Commit BOTH Locally and Remotely if you follow the steps as given below via git command line.

Run the following command to see the commit id that you want to revert

git log --oneline --decorate --graph

You will get like a following screenshot enter image description here

If you also check remote (via Web Interface) then you can see that this would be same as shown below

enter image description here

As per screenshot currently you are on commit id e110322 however you want to revert back to 030bbf6 BOTH LOCALLY and REMOTELY.

Perform the following steps to DELETE/REVERT Commits Locally+Remotely


First Locally Reverting to commit id 030bbf6

git reset --hard 030bbf6

followed by

git clean -f -d

These two commands clean force reset to commit stage 030bbf6 as shown below in snapshot

enter image description here

now if you run git status then you'll see that you are TWO Commits BEHIND from the remote branch as shown below enter image description here

Run following to update your indexes (if there are any updates). It is recommended that you ask all developers not to accept any pull requests on main remote branch.

git fetch --all

Once you are done with it then you are required to Push this commit forcefully by using + symbol in-front of branch as shown below. I have used here as master branch, you can replace it with any

enter image description here Code

git push -u origin +master

now if you see the web interface of remote then commit there should be reverted as well.

enter image description here

38
votes

2020 Simple way :

git reset <commit_hash>

(The hash of the last commit you want to keep).

You will keep the now uncommitted changes locally.

If you want to push again, you have to do :

git push -f
32
votes

Let's say 61234 is the sha-number of the last good commit you want to keep.

    git reset --hard 61234
    git push -f origin master 


 will remove completely all wrong commits without any trace.

Note: example assumed master branch on 'origin' remote.

23
votes
git revert HEAD -m 1

In the above code line. "Last argument represents"

  • 1 - reverts one commits.

  • 2 - reverts last two commits.

  • n - reverts last n commits.

You need to push after this command to take the effect on remote. You have other options like specifying the range of commits to revert. This is one of the option.


Later use git commit -am "COMMIT_MESSAGE" then git push or git push -f

14
votes

The reset hard worked for me: Thanks @Mo D Genensis and @vibs2006


git reset --hard 'your last working commit hash'

git clean -f -d

git push -f
3
votes

Here is my way:

Let's say the branch name is develop.

# Checkout a new temp branch based on one history commit
git checkout <last_known_good_commit_hash>

# Delete the original develop branch 
git branch -D develop
# Create a new develop branch based on the temp branch
git checkout -b develop

# Force update this new branch
git push -f origin develop

2
votes

You can do something like

git push origin +<short_commit_sha>^:<branch_name>
0
votes

Another way to do this without revert (traces of undo):

Don't do it if someone else has pushed other commits

Create a backup of your branch, being in your branch my-branch. So in case something goes wrong, you can restart the process without losing any work done.

git checkout -b my-branch-temp

Go back to your branch.

git checkout my-branch

Reset, to discard your last commit (to undo it):

git reset --hard HEAD^

Remove the branch on remote (ex. origin remote).

git push origin :my-branch

Repush your branch (without the unwanted commit) to the remote.

git push origin my-branch

Done!

I hope that helps! ;)

0
votes

To do it cleanly:

git rebase -i <hash of last good commit, 9 chars is enough>

Now you will get a list of the commits from the last good commit to the HEAD with options what to do with each commit. DROP will throw away that commit. Save the file.

Now to fix the upstream do :

git push --force-with-lease

(With lease so you don't accidentally cause problems for someone else working on your pushed update)

This keeps the log clean by removing the wrong commit instead of introducing new commits fixing earlier erroneous commits.