1051

I want to discard all changes done after commit <commit-hash> . So I did:

git reset --hard <commit-hash>

Now I want to do the same with my remote. How can I do this? I have done some commits (and pushes) after <commit-hash> and I just want to discard them all. Is just something went terribly wrong in the way and I don't want to make it worse than it is already. ;(

I basically want to rewind my origin/master to <commit-hash>

Adriaan Koster
  • 15,870
  • 5
  • 45
  • 60
nacho4d
  • 43,720
  • 45
  • 157
  • 240
  • 3
    Are you sure your `origin/master` has not been pulled and pushed to by other users? Changing history of a public (ie non-local) repository is something you want to avoid at all times. – vindia Apr 28 '11 at 09:54
  • Possible duplicate of [How to revert multiple git commits?](https://stackoverflow.com/questions/1463340/how-to-revert-multiple-git-commits) – Michael Freidgeim Sep 02 '18 at 08:25

11 Answers11

1845

Assuming that your branch is called master both here and remotely, and that your remote is called origin you could do:

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

However, you should avoid doing this if anyone else is working with your remote repository and has pulled your changes. In that case, it would be better to revert the commits that you don't want, then push as normal.

Update: you've explained below that other people have pulled the changes that you've pushed, so it's better to create a new commit that reverts all of those changes. There's a nice explanation of your options for doing this in this answer from Jakub Narębski. Which one is most convenient depends on how many commits you want to revert, and which method makes most sense to you.

Since from your question it's clear that you have already used git reset --hard to reset your master branch, you may need to start by using git reset --hard ORIG_HEAD to move your branch back to where it was before. (As always with git reset --hard, make sure that git status is clean, that you're on the right branch and that you're aware of git reflog as a tool to recover apparently lost commits.) You should also check that ORIG_HEAD points to the right commit, with git show ORIG_HEAD.

Troubleshooting:

If you get a message like "! [remote rejected] a60f7d85 -> master (pre-receive hook declined)"

then you have to allow branch history rewriting for the specific branch. In BitBucket for example it said "Rewriting branch history is not allowed". There is a checkbox named Allow rewriting branch history which you have to check.

Black
  • 18,150
  • 39
  • 158
  • 271
Mark Longair
  • 446,582
  • 72
  • 411
  • 327
  • 34
    Danger danger: this reset assumes that the corresponding (_tracking_) branch is currently checked out _and_ there are no uncommitted changes that you wanted to keep. **Use `git update-ref` instead of `reset --hard`**; it will allow you to do the same without having a working tree/checked out branch – sehe Apr 28 '11 at 09:59
  • 4
    I see. It has been pushed and changed by others. So I should use `revert ` but lets say I want to revert the past 4 commits so I should do `git revert comit1; git push; git revert comit2; git push; ...` or simply `git revert commit4; git push`? – nacho4d Apr 28 '11 at 10:06
  • @sehe: I stated my assumptions, and note that @nacho4d has **already run** the `git reset --hard` comment. I agree that `git reset --hard` is dangerous in general, but recommending that most git users use the plumbing command `git update-ref` is a very bad idea - it's difficult to use correctly and there are no safety checks. – Mark Longair Apr 28 '11 at 10:33
  • 1
    @nacho4d: you don't need to push after each revert - there's a nice description of what to do in [this answer from Jakub Narębski](http://stackoverflow.com/questions/1463340/revert-multiple-git-commits/1470452#1470452). You do need to revert each commit going backwards - just doing `git revert commit4` creates a new commit that only undoes the changes that were introduced in `commit4`. As the answer I linked to points out, though, you can roll these into a single commit. – Mark Longair Apr 28 '11 at 10:34
  • Hmmm ok, fair point. I never considered `update-ref` to be plumbing (but then, I don't consider `mov 01,%eax` plumbing) – sehe Apr 28 '11 at 10:36
  • 1
    @Mark I have already run `git reset --hard` but I have deleted my local and pulled from origin again so I am able to do `git revert ...` My doubt now is: do I have to revert each commit and push (one by one) or just revert the first commit after the right commit only? – nacho4d Apr 28 '11 at 10:38
  • @Mark: Wait... did you say update-ref is difficult to use correctly and has no safety checks? It has a hell of a lot _MORE_ safety checks than git reset, will allow you to document the reflog entry with a reason, and by the way, where's the safety check on `push -f`? – sehe Apr 28 '11 at 10:48
  • 1
    @sehe: it's difficult to use because you need to use the full ref name, and so it's easy for people to litter their `.git` directory with refs that they didn't mean to create. I was wrong to say that there are no safety checks, though. You can find the classification into "plumbing" and "porcelain" commands in the [git man page](http://www.kernel.org/pub/software/scm/git/docs/#_git_commands). – Mark Longair Apr 28 '11 at 10:55
  • 1
    @nacho4d: I updated my answer, and I hope that the revised answer and my comment above answer that. – Mark Longair Apr 28 '11 at 10:57
  • @Mark: ok, thanks for the discussion, and @nacho4d: sorry for highjacking your question, in a way :_) – sehe Apr 28 '11 at 11:01
  • You need to have the 'ForcePush' permission to perform the `push -f` – sonyisda1 Sep 22 '17 at 12:56
  • 1
    FYI, if you're using Github and the master branch is protected, you'll have to disable that in order to `git push -f`. – Joshua Pinter Jan 12 '18 at 16:57
  • For a little clarity, will `git reset --hard ORIG_HEAD` reset my _local_ branch to the commit pointed at by `ORIG_HEAD`, or will it reset `ORIG_HEAD` _on the remote_ to a specified commit with `` after it? I know I'm the only one working on this branch, and my goal is to wipe out commit history after a given commit. – PaulBunion Jan 14 '22 at 14:23
  • What to do if the remote rejects force-pushing? The 1st step, git reset, worked fine, but the 2nd step, git push -f, was rejected. – Michael Sep 24 '22 at 00:36
220

Using some other answers can result in unnecessary loss of local state. Local changes are not inherently required to change a remote. This method can still wreck your remote if you choose the wrong commit to go back to, but even then you can usually find the right commit and try again.

You must have the desired commit somewhere in your local repo that you want the remote to match.

  1. Do not do any resetting.
  2. Use git log to find the commit you want to the remote to be at. Use git log -p to see changes, or git log --graph --all --oneline --decorate to see a compact tree.
  3. Copy the commit's hash, tag, or (if it's the tip) its branch name.
  4. Run a command like:
    git push --force <remote> <commit-ish>:<the remote branch>
    
    e.g.
    git push --force origin 606fdfaa33af1844c86f4267a136d4666e576cdc:master
    
    or
    git push --force staging v2.4.0b2:releases
    

If the forced push fails, it's likely disabled by the remote. This may be worked around by temporarily changing one or both of receive.denyNonFastForwards and receive.denyDeletes. If your remote is hosted on a service without shell access, it probably has settings you can change to allow forced pushes.


I use a convenient alias (git go) for viewing history as in step 2, which can be added like so:

git config --global alias.go 'log --graph --all --decorate --oneline'
Walf
  • 8,535
  • 2
  • 44
  • 59
  • 4
    The graph was a very nice tip, I just added -5 to get only the last n commits, it was a huge tree else. Also avoiding the reset is just what I was looking for. Great – AlexanderD Dec 12 '17 at 11:11
  • 1
    This is perfect. I have always mess up my local. This was exactly what I needed after accidently pushing my staging to live :( Thanks! – Jake Feb 23 '18 at 21:52
  • 2
    On Windows, enter `q` to exit the git log. 2 minutes i'll never get back. – dst3p Jan 17 '19 at 21:50
  • 1
    @dst3p That's on every platform, mate. The pager program is usually `less` and `q` is the normal way to exit it. Git Bash is like a *nix terminal. – Walf Jan 18 '19 at 01:16
  • 1
    @Walf thanks! I was on Windows at the time so didn’t want to make any assumptions. :) – dst3p Jan 18 '19 at 01:30
  • Nice use of commit-ish. – IEnjoyEatingVegetables Aug 18 '23 at 20:51
83

I solved problem like yours by this commands:

git reset --hard <commit-hash> 
git push -f <remote> <local branch>:<remote branch> 
Ibrohim Ermatov
  • 2,169
  • 19
  • 13
37

On GitLab, you may have to set your branch to unprotected before doing this. You can do this in [repo] > Settings > Repository > Protected Branches. Then the method from Mark's answer works.

git reset --hard <commit-hash>
git push -f origin master
dudasaus
  • 651
  • 6
  • 6
22

If you want a previous version of file, I would recommend using git checkout.

git checkout <commit-hash>

Doing this will send you back in time, it does not affect the current state of your project, you can come to mainline git checkout mainline

but when you add a file in the argument, that file is brought back to you from a previous time to your current project time, i.e. your current project is changed and needs to be committed.

git checkout <commit-hash> -- file_name
git add .
git commit -m 'file brought from previous time'
git push

The advantage of this is that it does not delete history, and neither does revert a particular code changes (git revert)

Check more here https://www.atlassian.com/git/tutorials/undoing-changes#git-checkout

priya khokher
  • 640
  • 7
  • 14
  • This is an excellent answer: it works, period and is very safe; if you mess it up it's easy to go back. – bob Oct 01 '19 at 20:19
  • This should be added to the accepted answer. Much better. – Flux Dec 10 '21 at 07:49
  • Agree, this is the correct way of doing it as no history is rewritten and no risk of commits getting lost. We should avoid using force-commits as much as possible. – Hans Apr 16 '22 at 11:19
14

I faced the same problem recently and it got resolved with two steps:

  1. Reset it to local git with git reset --hard HEAD~1 here HEAD~1 is most recent commit.
  2. Push that in to the desired branch forcefully git push -f origin main.

That's it.

ouflak
  • 2,458
  • 10
  • 44
  • 49
Shailesh Parmar
  • 161
  • 1
  • 6
  • 1
    This is not a good practice if you work on a team provided that if other people have pulled the branch they will need to do a `git rebase` because pull would give them a "divergent branches" conflict – Josep Alsina Jul 01 '22 at 10:13
  • 1
    @JosepAlsina Granted it is not a best practice but stiil very usefull if you accidentally pushed a bad commit and want to delete all history. – Mendrika Sandratra Feb 21 '23 at 14:47
10

My two cents to the previous answers: if

git push --force <remote> <the-hash>:<the remote branch>

still doesn't work, you might want to edit <your-remote-repo>.git/config file's receive section:

[receive]
  #denyNonFastforwards = true
  denyNonFastforwards = false
badbishop
  • 1,281
  • 2
  • 18
  • 38
  • It's helpful to know how to configure a remote to allow non-fast-forward pushes as most answers seem to assume a remote service like github or bitbucket. – strongbutgood Dec 22 '19 at 01:48
9

Let's assume that your branch is called master both locally and remotely, and that your remote is called origin you could do:

git reflog to get all the commit history, your commit hash has format like this: e34e1ff

git reset --hard <commit-hash>

git push -f origin master
Blessing
  • 2,450
  • 15
  • 22
3

Sourcetree: resetting remote to a certain commit

  1. If you have pushed a bad commit to your remote (origin/feature/1337_MyAwesomeFeature) like below picture

Go to Remotes

  1. Go to Remotes > origin > feature > 1337_MyAwesomeFeature
  2. Right click and choose "Delete origin/feature/1337_MyAwesomeFeature" (Or change name of it if you want a backup and skip step 4.)
  3. Click "Force delete" and "OK".

enter image description here enter image description here

  1. Select your older commit and choose "Reset current branch to this commit"
  2. Choose which mode you want to have (Hard if you don't want your last changes) and "OK".

enter image description here enter image description here

  1. Push this commit to a new origin/feature/1337_MyAwesomeFeature enter image description here

  2. Your local feature branch and your remote feature branch are now on the previous (of your choice) commit enter image description here

Joel Wiklund
  • 1,697
  • 2
  • 18
  • 24
2

If your branch is not development or production, the easiest way to achieve this is resetting to a certain commit locally and create a new branch from there. You can use:

git checkout 000000

(where 000000 is the commit id where you want to go) in your problematic branch and then simply create a new branch:

git remote add [name_of_your_remote]

Then you can create a new PR and all will work fine!

Gerardo Suarez
  • 352
  • 2
  • 13
1

Do one thing, get the commit's SHA no. such as 87c9808 and then,

  1. move yourself ,that is your head to the specified commit (by doing git reset --hard 89cef43//mention your number here )
  2. Next do some changes in a random file , so that the git will ask you to commit that locally and then remotely Thus, what you need to do now is. after applying change git commit -a -m "trial commit"
  3. Now push the following commit (if this has been committed locally) by git push origin master
  4. Now what git will ask from you is that

error: failed to push some refs to 'https://github.com/YOURREPOSITORY/AndroidExperiments.git' 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.**

  1. Thus now what you can do is

git push --force origin master

  1. And thus, i hope it works :)
Aᴍɪʀ
  • 7,623
  • 3
  • 38
  • 52
Siddharth Choudhary
  • 1,069
  • 1
  • 15
  • 20