59

I have three commits I made which I attempted to clean up some code. Anyways I managed to completely destroy what I was working on. And I want to delete the past three commits and return to a specific commit SHA1.

How can I restore to that previous commit and delete the history of those 3 commits? (The history deleting part is not a big deal). These commits are pushed already, so I am a little lost.

Thanks!

Steven
  • 13,250
  • 33
  • 95
  • 147
  • you have 3 local commits and you want to go back and erase them forever? are these commits pushed remotely? – Pablo Fernandez Mar 19 '12 at 02:36
  • Yes they are pushed remotely. Which is why I am confused. And I want them gone forever. – Steven Mar 19 '12 at 02:37
  • This usually is not a good idea, if you make an error you can erase your coworkers commit, of course if you are working alone this should not be a problem.. To be safe is better to only do a git revert, the commits will still be there but the code will be ok. – Dimas Kotvan Sep 20 '13 at 16:33
  • possible duplicate of [Revert to previous Git commit](http://stackoverflow.com/questions/4114095/revert-to-previous-git-commit) – Brad Werth Jun 09 '14 at 20:35

6 Answers6

80

Find the commit you want to reset to:

git log

Once you have the hash:

git reset --hard <hash>

And to push onto the remote:

git push -f <remote> <branch>
triad
  • 20,407
  • 13
  • 45
  • 50
41

Since your commits are pushed remotely you need to remove them. I'll assume your branch is master and it's pushed over origin.

You first need to remove master from origin:

git push origin :master (note the colon)

Then you need to get master to the status you want, I'll assume the commit hash is ABCDE:

git reset --hard ABCDE

Lastly, push master again:

git push origin master

That's it! Note that if someone already downloaded your changes from origin this will screw them pretty much leaving their local repos unstable.

Pablo Fernandez
  • 103,170
  • 56
  • 192
  • 232
  • 6
    This looked helpful so I just tried it, but I got this error after `git clone git@github.com:dandv/reveal.js.git` and `git push origin :master `: > remote: error: refusing to delete the current branch: refs/heads/master To git@github.com:dandv/reveal.js.git ! [remote rejected] master (deletion of the current branch prohibited) error: failed to push some refs to 'git@github.com:dandv/reveal.js.git' – Dan Dascalescu Nov 13 '12 at 09:20
  • 1
    Don't you need to do git push -f origin master? You say "note the colon" but what does it do? – Erick Maynard May 09 '18 at 22:38
22

The general idea in git is that you never delete a commit. You just leave them without a name. Commits that are neither named nor referenced by some other named commit, eventually go away on their own.

For example, suppose you started with:

$ git checkout my_work_branch
<do some editing>
$ git commit -m "attempt #1, so far so good"
<do more editing>
$ git commit -m "attempt #2, getting a little hazier"
<do more editing>
$ git commit -m "attempt #3, looking bleak now"

At this point git log --graph --decorate --pretty=oneline --abbrev-commit might produce something like:

* d97de0e (HEAD, my_work_branch) attempt #3, looking bleak now
* 9a3efe3 attempt #2, getting a little hazier
* 9e80936 attempt #1, so far so good
* a1d6424 here's where you started

What you have now is that the branch named my_work_branch (the name you gave earlier) "points to" commit d97de0e, which in turn points to 9a3efe3, which points to 9e80936, which points to a1d6424. (This is also where the special name HEAD points.)

You can move HEAD elsewhere with any old git checkout. But, here's the thing: you can also move the name my_work_branch to point to a1d6424 too:

$ git reset --hard a1d6424

or

$ git reset --hard HEAD~3  # use at most one of these

If you do this, you find that the name my_work_branch has also been moved:

$ git rev-parse my_work_branch
a1d6424e5afcda475910084720c9aa26e3528618

The commits you added are still there:

$ git log d97de0e

will show it them to you:

$ git log --graph --decorate --pretty=oneline --abbrev-commit d79de0e
* d97de0e attempt #3, looking bleak now
* 9a3efe3 attempt #2, getting a little hazier
* 9e80936 attempt #1, so far so good
* a1d6424 (HEAD, my_work_branch) here's where you started

It's just that they no longer have any names, and if you do some work and git add and git commit it, that will be on a new branch named my_work_branch. The old one, that has the three extra commits, is now a "junk" branch. (If you decide that despite the bleakness you want them back, you need only give them a name before they expire in roughly 3 months. You'll have to find or remember that number, d97de0e in the above example, somehow.)


Update: ah, you've pushed them and you want them gone from the remote repository.

You don't have to delete the remote branch. You can use git push -f after doing the rewind (git reset --hard) above. Just remember that anyone else who has fetched your pushed changes has them, and will continue to have them and can easily get confused by their presence. You'll have to alert any such people to beware of your "revoked" commits.

torek
  • 448,244
  • 59
  • 642
  • 775
15

Ok, here are two solutions.

For either solution, git log and find the hash of the commit you want to go back to.

1) Revert your changes by automatically creating a patch to undo them.

What? Automatically create a reverse patch to undo your changes. Commit and push the patch. Your original changes are still in the git log, but they are "undone" with this reverse patch.

How? git revert [hash] && git push

Why? Because you are a nice dev working with other nice devs and don't want to wreck their local repos.

Why not? Because it's harder to "merge" your changes later. The revert patch is "newer" than your changes, so it's harder than "git merge" to re-apply your changes.

2) Force push to a previous commit

What? A branch is a pointer to a commit. Hard reset that pointer to a previous commit, then force push that pointer to the server. Your changes (and anyone elses) are removed from the git history.

How? git reset --hard [hash] && git push -f

Why? Because you're a wild cowboy/cowgirl and your changes are in a feature branch you'd like to keep working on to easily merge later.

Why not? Your reset and push will mess up any local repos for teammates that already pulled your changes (e.g. losing their commits, having to recommit work). If you haven't pushed (or they haven't pulled), not a problem.

Michael Cole
  • 15,473
  • 7
  • 79
  • 96
2

use git revert

-- you can revert to one, two or range of commit

-- it will delete the commit history also

1) git revert 175a25

2) git status / git log (to confirm you have reverted)

3) git push

  • This creates a reverse patch to remove the changes. This patch is better for other developers (e.g. anyone who pulled the changes you're reverting), but it also means you can't merge the changes in later (because the reverse patch is "newer"). – Michael Cole Jan 06 '19 at 04:03
0

For example, if you want to get rid of the last two commits, you can do this:

git log -3
commit 7e83c9fa5dc1a1914847bfccfe9d2da14f845070
Author: Jaime Montoya <webmaster@jaimemontoya.com>
Date:   Fri Sep 28 05:58:58 2018 -0600

    Add new background image to the header of the website.

commit b84b0c38df2f876d1c1f5657e6e452b5689c2d80
Author: Shannon Hall <s.hall@example.net>
Date:   Thu Sep 27 21:35:48 2018 -0400

    Include code for Google Maps.

commit 40e82f46c1d523cb07abb6abe9f8c64f2b4fe0f7
Author: Jaime Montoya <webmaster@jaimemontoya.com>
Date:   Thu Sep 27 18:57:45 2018 -0600

    Update links to copyright messages.

In this case, we are trying to get rid of these two commits: 7e83c9fa5dc1a1914847bfccfe9d2da13f845070 and b84b0c38df2f876d1c1f5657e6e255b5689c2d80. We want to have this as our latest commit: 40e82f46c1d523cb07abb6abe9f8c64f2b4fe0f7. We need to do this:

git reset --hard 40e82f46c1d523cb07abb6abe9f8c64f2b4fe0f7

This is one way to undo commits from your local repository.

After the above you push to your remote repository by using git push <remote> <branch>.

Jaime Montoya
  • 6,915
  • 14
  • 67
  • 103