0

Consider this Git repository:

$ git log -4

commit d7a65d3243259300ff133a28e952fd967df8ff24
Merge: 5572899 65d0d65
Date:   Sun Jul 20 08:23:09 2014 -0400

    Merge branch 'master' of ssh://foo/bar

commit 5572899e00f24f1d6ebc4435ef167508be2dbb47
Date:   Sun Jul 20 07:55:48 2014 -0400

    Commit changes done on server

commit 65d0d65b50a28388ff9073dd6973ee5d115fa141
Date:   Sun Jul 20 14:31:01 2014 +0300

    conflict 21

commit a3c6295de542ae510623921b188be1ef5bb25428
Date:   Sun Jul 20 13:12:39 2014 +0300

    Update spam filter

I need to return the code of the repository to the state that it was in at commit a3c6295de542ae510623921b188be1ef5bb25428. The repository is shared among other developers, all have pulled. What is the proper way to return the repo to the state of the desired commit?

Simply doing git reset --hard a3c629 will not work as I cannot then push the repo:

$ git push
To ssh://foo/bar.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'ssh://foo/bar.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

I don't want to rebase as there are other developers. What else can I do?

dotancohen
  • 30,064
  • 36
  • 138
  • 197
  • You can reset. Git is warning you to update a ref to an older or different commit because other _might_ have based newer commits on it. But sometimes it's necessary to force-push a branch. Then you should communicate that to your peers. They then perhaps need to rebase their commits onto the new HEAD. Force-push can be done just by preceeding the branch name with a plus sign: `git push +`. Peer developers then need to e.g. `git rebase --onto / HEAD~` – try-catch-finally Jul 20 '14 at 12:55
  • 1
    git revert is the proper way – Martin G Jul 20 '14 at 13:04
  • I highly recommend that you see the [top voted answer here](http://stackoverflow.com/a/4114122/456814), it offers additional solutions to your problem. –  Jul 22 '14 at 15:49

1 Answers1

3

You can try a "forced" revert, meaning creating a new commit, except that new commit would reflect a3c6295d, instead of trying to cancel the subsequent commits:

# move HEAD, reset index
git reset a3c6295de542ae510623921b188be1ef5bb25428

# force the files to be like the index
git checkout -- .

# move HEAD back to its previous place
git reset --soft @{1}

# commit the current index (which should reflect a3c6295d)
git commit -m "restore a3c6295de542ae510623921b188be1ef5bb25428"

git push

That way, no need to force the push.


The question "Revert to a previous Git commit" proposes a simpler solution, without having to move HEAD from your most recent commit:

# restore directly the right commit
git checkout a3c6295de542ae510623921b188be1ef5bb25428 -- .

# commit the current index (which should reflect a3c6295d)
git commit -m "restore a3c6295de542ae510623921b188be1ef5bb25428"

Both solutions do the same: create a new commit on top of HEAD, which is useful considering HEAD was already pushed to a remote repo and its history shouldn't be changed.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Thank you! The comments detailing each step is very helpful. – dotancohen Jul 20 '14 at 13:03
  • For your second set of commands, I think you might actually need to run `git rm -r -- .` first before the checkout, otherwise you'll end up keeping any files that were added after the commit that you're trying to revert back to. –  Jul 22 '14 at 15:27