265

I've read the similar posts on this topic, and can't for the life of me figure out how to do this properly.

I checked in about 1000 files that I don't want, and I'd rather not have to go through 1by1 and remove them all from the repo.

  • I have a remote master Branch.
  • I have the local master Branch.

They are both at the same revision.

I want to rollback my remote by 1 commit.

Say my history on master is A--B--C--D--E.
I want to rollback my local to D.
Then push it to remote so my current hash will be D both remote and local.

I'm having issues doing this.
I'm using Git Tower but am comfortable with the command line. Any help?

UPDATE: Great comments below. Using a reset seems to be partially discouraged especially if the repository is shared with other users. What's the best way to undo the previous commit's changes without using a hard reset? Is there a way?

Jamis Charles
  • 5,827
  • 8
  • 32
  • 42
  • I have updated my answer to "undo the previous commit's changes without using a hard reset". – VonC Jan 10 '11 at 18:40
  • 3
    Use `git revert` for doing without hard resets and without disturbing users. – user562374 Jan 10 '11 at 20:58
  • 1
    Rolling back the remote is what is discouraged, but if that's what you want to do, do it. There's hundreds of ways to do that, but the result would be the same on the server side. – FelipeC Jun 07 '19 at 04:33

15 Answers15

427

If nobody has pulled your remote repo yet, you can change your branch HEAD and force push it to said remote repo:

git reset --hard HEAD^ 
git push -f 

(or, if you have direct access to the remote repo, you can change its HEAD reference even though it is a bare repo)

Note, as commented by alien-technology in the comments below, on Windows (CMD session), you would need ^^:

git reset --hard HEAD^^
git push -f 

And? as noted in the comments by Jon Schneider:

If the command with "HEAD^" results in error no matches found: HEAD^, see "git show HEAD^ doesn't seem to be working. Is this normal?"

Update since 2011:
Using git push --force-with-lease (that I present here, introduced in 2013 with Git 1.8.5) is safer.

See Schwern's answer for illustration.


What if somebody has already pulled the repo? What would I do then?

Then I would suggest something that doesn't rewrite the history:

  • git revert locally your last commit (creating a new commit that reverses what the previous commit did)
  • push the 'revert' generated by git revert.
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    What if somebody has already pulled the repo? What would I do then? – Jamis Charles Jan 10 '11 at 17:46
  • @Jamis: I have updated my answer to include the case you mention. – VonC Jan 10 '11 at 17:54
  • 1
    Perfect. Exactly what I was looking for. Found some great usage examples here: http://book.git-scm.com/4_undoing_in_git_-_reset,_checkout_and_revert.html >> git revert HEAD This will undo all of the changes from the previous commit. You can then commit those undone changes. – Jamis Charles Jan 11 '11 at 03:43
  • 1
    @gwho creates a branch? No it moves the HEAD of a branch, but you are still in the same branch. However, since the push is no longer a fast-forward one, yes, you need to force that push. – VonC Jul 01 '14 at 09:28
  • Normally, using the reset command diverges the commit chain of your branch. In other words, committing additional commits adds on to this diverged "line" of commits, rather than to the commit you were trying to "undo". This tends to break things. I did this for the remote repository as advised in this answer, but then had issues pushing to heroku from the remote resository (e.g. github). I had to do `git push heroku master -f` as well. Something to keep in mind. – – ahnbizcad Jul 01 '14 at 09:35
  • 1
    is there a way to know if somebody has pulled the repo? – Lv99Zubat Jul 05 '16 at 19:26
  • @Rai not with git alone. You need to check the logs of the listener on the server side (Apache, or ssh gitolite) – VonC Jul 05 '16 at 19:28
  • 4
    In Windows, the ^ character is used for line continuation and to escape a character, making the command: git reset --hard HEAD^^ – Alien Technology Jul 20 '16 at 17:15
  • @AlienTechnology Thank you. I have edited the answer to make that clearer. – VonC Jul 20 '16 at 18:27
  • 1
    @AlienTechnology Using Powershell, on windows 10, I only had to type `reset --hard HEAD^` and not `reset --hard HEAD^^` to reset the last commit. – Puka Jan 30 '19 at 13:04
  • If the command with "HEAD^" results in error `no matches found: HEAD^`, see: https://stackoverflow.com/q/6091827/12484 – Jon Schneider Oct 14 '21 at 14:16
  • 1
    @JonSchneider Thank you, good point. I have included your comment in the answer for more visibility. – VonC Oct 14 '21 at 14:22
78

Set the local branch one revision back (HEAD^ means one revision back):

git reset --hard HEAD^

Push the changes to origin:

git push --force

You will have to force pushing because otherwise git would recognize that you're behind origin by one commit and nothing will change.

Doing it with --force tells git to overwrite HEAD in the remote repo without respecting any advances there.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
eckes
  • 64,417
  • 29
  • 168
  • 201
  • Great answer. I've read that using a reset seems to be partially discouraged especially if the repository is shared with other users. Is there a cleaner way to do this, that undoes all of your previous commit's changes? – Jamis Charles Jan 10 '11 at 17:44
  • Be careful! Stash your uncommitted changes or your lost them – Nosov Pavel Jul 25 '17 at 14:36
  • That's cool. So, does this mean that when we do `git push origin master`, Git is able to create a new commit at the remote because the local branch is ahead by at least once commit? Furthermore, the latter must be substantively different from what the head at the remote repo points to? – MadPhysicist Nov 02 '19 at 04:38
21

If you want revert last commit listen:

Step 1:

Check your local commits with messages

$ git log

Step 2:

Remove last commit without resetting the changes from local branch (or master)

$ git reset HEAD^

OR if you don't want last commit files and updates listens

$ git reset HEAD^ --hard

Step 3:

We can update the files and codes and again need to push with force it will delete previous commit. It will keep new commit.

$ git push origin branch -f

That's it!

JRodDynamite
  • 12,325
  • 5
  • 43
  • 63
Kannan S
  • 2,459
  • 1
  • 17
  • 17
  • 2
    That's not _reverting_ a commit, it's replacing one. Please don't confuse us git novices by misusing conventional terms. – Suncat2000 Feb 26 '18 at 16:35
11

By entering bellow command you can see your git commit history -

$ git log

Let's say your history on that particular branch is like - commit_A, commit_B, commit_C, commit_D. Where, commit_D is the last commit and this is where HEAD remains. Now, to remove your last commit from local and remote, you need to do the following :

Step 1: Remove last commit locally by -

$ git reset --hard HEAD~

This will change your commit HEAD to commit_C

Step 2: Push your change for new HEAD commit to remote

$ git push origin +HEAD

This command will delete the last commit from remote.

P.S. this command is tested on Mac OSX and should work on other operating systems as well (not claiming about other OS though)

sahilabrar
  • 638
  • 1
  • 8
  • 15
11

Here's an updated version of the procedure which is safer.

git reset --hard HEAD^ 
git push --force-with-lease

git push -f will indiscriminately replace the remote repository with your own changes. If someone else has pushed changes they will be lost. git push --force-with-lease will only push your rebase if the repository is as you expect. If someone else has already pushed your push will fail.

See –force considered harmful; understanding git’s –force-with-lease.

I recommend aliasing this as repush = push --force-with-lease.

What if somebody has already pulled the repo? What would I do then?

Tell them to git pull --rebase=merges. Instead of a git fetch origin and git merge origin/master it will git fetch origin and git rebase -r origin/master. This will rewrite any of their local changes to master on top of the new rebased origin/master. -r will preserve any merges they may have made.

I recommend making this the default behavior for pulling. It is safe, will handle other's rebasing, and results in less unnecessary merges.

[pull]
        rebase = merges
Schwern
  • 153,029
  • 25
  • 195
  • 336
  • I thought I did that already (yesterday): https://stackoverflow.com/posts/4647362/revisions – VonC Feb 01 '20 at 01:17
5

**Answering very shortly about revert and reset **

There are many way you can do this. Based on your requirement choose anything from below.

1. By REVERTing commit:

If you want to REVERT all the changes from you last COMMIT that means If you ADD something in your file that will be REMOVED after revert has been done. If you REMOVE something in your file the revert process will ADD those file.

You can REVERT the very last COMMIT. Like:

1.git revert HEAD^
2.git push origin <Branch-Name>

Or you can revert to any previous commit using the hash of that commit.Like:

1. git revert <HASH>
2.git push origin  <Branch-Name>

Or if the commit is a merge commit you can try this:

1.git revert -m 1 <HASH> (-m 1 refers to the first parent of two merged branches)
2.git push origin  <Branch-Name>

2. By RESETing previous Head

If you want to just point to any previous commit use reset; it points your local environment back to a previous commit. You can reset your head to previous commit or reset your head to previous any commit.

Reset to very last commit.

1.git reset HEAD^
2.git push -f origin <Branch-name>

Reset to any previous commit:

1.git reset <HASH>
2.git push -f origin <Branch-name>

Trade of between REVERT & RESET:

  1. Why would you choose to do a revert over a reset operation? If you have already pushed your chain of commits to the remote repository (where others may have pulled your code and started working with it), a revert is a nicer way to cancel out changes for them. This is because the Git workflow works well for picking up additional commits at the end of a branch, but it can be challenging if a set of commits is no longer seen in the chain when someone resets the branch pointer back.

  2. And resetting a branch can be destroying what you have done till now.Because when you reset a commit, GIT will delete all the commits that have done after this commit.One silly mistake can destroy all your hard work and it doesn't keep any history what you are resetting. On the other hand reverting a commit is better option in this scenario. When you revert a commit, GIT creates a new commit with the completely opposite changes of the commit you are willing to revert.And it points to the end of that branch. So it won't mess up anything on our silly mistake.

Azahar Alam
  • 708
  • 5
  • 16
4

For Windows Machines, use:

git reset HEAD~1  #Remove Commit Locally
Anvesh Yalamarthy
  • 1,625
  • 20
  • 36
2

You can also do this:

git reset --hard <commit-hash>
git push -f origin master

and have everyone else who got the latest bad commits reset:

git reset --hard origin/master
A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
1

I solved problem like yours by this commands:

git reset --hard HEAD^
git push -f <remote> <local branch>:<remote branch> 
Ibrohim Ermatov
  • 2,169
  • 19
  • 13
0

If you have direct access to the remote repo, you could always use:

git reset --soft HEAD^

This works since there is no attempt to modify the non-existent working directory. For more details please see the original answer:

How can I uncommit the last commit in a git bare repository?

Community
  • 1
  • 1
Hazok
  • 5,373
  • 4
  • 38
  • 48
0

I just wanted to remove last commit from remote and clear commit history also. The following worked like a charm

git reset --hard HEAD^ 
git push -f 
minhas23
  • 9,291
  • 3
  • 58
  • 40
  • But how "the following" is any different from [my answer above](http://stackoverflow.com/a/4647362/6309)? – VonC Aug 12 '15 at 08:36
0

The way to reset the head and do the revert to the previous commit is through

$ git reset HEAD^ --hard
$ git push <branchname> -f

But sometimes it might not be accepted in the remote branch:

To ssh:<git repo>
 ! [rejected]        develop -> develop (non-fast-forward)
error: failed to push some refs to 'ssh:<git repo>'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

then the other way to do is

git revert HEAD
git push <remote branch>

This works fine.

NOTE: remember if the git push -f <force> failed and then you try to revert. Do a git pull before, so that remote and local are in sync and then try git revert.
Check with git log to make sure the remote and local are at same point of commit with same SHA1..

git revert 
A --> B --> C -->D
A--> B --> C --> D --> ^D(taking out the changes and committing reverted diffs)
Mr Lister
  • 45,515
  • 15
  • 108
  • 150
ravi.zombie
  • 1,482
  • 1
  • 20
  • 23
0

on local master

git reflog
-- this will list all last commit
  e.g Head@{0} -- wrong push
      Head@{1} -- correct push  
git checkout Head@{1} .
  -- this will reset your last modified files

git status 
git commit -m "reverted to last best"
git push origin/master

No need to worry if other has pulled or not.

Done!

Bhushan
  • 71
  • 5
0

If you only want to remove the last commit from the remote repository without messing up with your local repository, here's a one-liner:

git push origin +origin/master~:master

This uses the following syntax:

git push <remote> <refspec>

Here, <remote> is origin, and <refspec> has the following structure:

+origin/master~:master

Details can be found in git-push(1). The preceding + means "force push this ref", and the other part means "from origin/master~ to master (of remote origin)". It isn't hard to know that origin/master~ is the last commit before origin/master, right?

iBug
  • 35,554
  • 7
  • 89
  • 134
0

for me works this two commands:

git checkout commit_id
git push origin +name_of_branch
Yahor M
  • 617
  • 8
  • 8