1

I'm trying to remove two last commits via rebase/cherry-pick. After invoking git rebase HEAD^^^ -i I'm leaving only necessary commit (leaving everything up to HEAD^^, so I'm dropping HEAD^ and HEAD).

After the git push I see the following:

! [rejected]        dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:XXXXXX/YYYYYYYYY.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.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

But git pull just fast-forwards ho former HEAD commit. So, I'm ending up with what I've started with. What am I doing wrong?

eykanal
  • 26,437
  • 19
  • 82
  • 113
igorp1024
  • 1,103
  • 2
  • 12
  • 19

2 Answers2

5

It's not about cherry-picking, it's about rebasing. After the rebase, your local and remote branches will have diverged, requiring a merge. Git will never perform a merge on the remote (unless it's a fast-forward merge, meaning only one branch has advanced), so it requires you to pull and do the merge locally.

The thing is, a merge isn't what you want. You explicitly want to discard the "diverged" commits on the remote branch, and overwrite it with the state of your local branch.

You can do so with git push -f, but you should only do this if you're not sharing this branch with other people. Otherwise, they'll wind up pulling your changes down, merging them with their own diverged copies, and reintroducing the commits you're trying to remove.

If you are sharing this repository with other people who may have the branch checked out, you have two options.

Either...

  • force-push anyways, and then contact each person collaborating on that branch and advise them to discard their local copy. Send them this one-liner, and advise them to stash any changes they might have:

    $ git fetch && git checkout dev && git reset --hard origin/dev
    

    After doing this, they may have lost commits on their local dev branch; they can recover them with cherry-picking.

or...

  • Don't do what you're trying to do. You shouldn't be rewriting history on a shared branch, it just creates a hassle for everybody else.
user229044
  • 232,980
  • 40
  • 330
  • 338
  • 1
    What if he is sharing his branch with other people? Then what? – Daniel Kaplan Jul 16 '14 at 21:05
  • So, for instance if I'd dropped HEAD^ then there will be no necessity of asking others to discard their local copy? – igorp1024 Jul 16 '14 at 21:13
  • Thanks for the update, but there's something unsatisfying about that. Contacting everyone also seems difficult in certain situations. Isn't this an option: Discard your local changes and try again without rewriting local history. Maybe that's what the 2nd bullet point is trying to say. In summary, *is there a way to undo remote history you changed that you haven't pushed out yet?* EG: "Remember that commit --amend? Turn that into a regular commit"" "Remember that squash? Unsquash that" – Daniel Kaplan Jul 16 '14 at 21:15
  • 1
    @igorp1024 No, if you rebase *any* commit out, you need to force-push, and then everybody else needs to discard their local copy. It's the force-push that requires other people to discard their local branches, and the only way you can remove commits from a branch without a force-push is if you haven't already pushed those commits on that branch. – user229044 Jul 16 '14 at 21:15
  • @tieTYT There *is* another option: It's `git revert`. But that doesn't remove the commits, it adds *new* commits which apply the opposite changes to nullify earlier commits. – user229044 Jul 16 '14 at 21:16
  • @tieTYT And yes, there are lots of better ways than rebasing, if you cannot force-push. Undoing a `commit --amend` is particularly easy, but it's all outside the scope of this question. The question is about rebasing, and that's the question I'm answering. I cannot guess at and address every possible scenario that might have prompted the OP to want to rebase a commit out of their branch. – user229044 Jul 16 '14 at 21:18
  • @meagar that's fair, I'm derailing the answer for my own education. I'll look for a relevant question / ask my own. – Daniel Kaplan Jul 16 '14 at 21:20
1

This is what revert is for. You can revert the last two commits, which keeps the old ones in the graph and creates new commits to undo their contents, which does not rewrite history but produces the effect.

Or you can rewrite history and suffer the consequences.

Edward Thomson
  • 74,857
  • 14
  • 158
  • 187
  • Actually I tried to avoid extra commit because last commits were considered as error-prone. But I understand that it is bad to rewrite the history from shared branch. Thanks anyway. – igorp1024 Jul 17 '14 at 08:59