3

While working on an open source project I encountered the following issue with git. I made a few changes, and sent a pull-request. The PR was accepted at first. However, my changes turned out to have some subtle bugs and the maintainer reverted my commits again, asking me to send a new pull-request once I've fixed the issue. However, a lot of other commits have happened in between, so I need to update my pull-request. Unfortunately, I cannot get git to rebase or cherry-pick my old PR on top of the most recent state of master.

Let me clarify things with an example. Say, my original pull-request had commits A, and B and was accepted. Then, a few commits later my PR was reverted (R), and then a few more commits happened. The history looks like this:

...--A---B--...--R--...--o master

Now, I want to transform it to the following form, in order to refine my pull-request on top of the most recent state of master:

...--A---B--...--R--...--o master
                          \
                           A---B newPR

However, I failed to achieve this with both rebase, and cherry-pick. The problem seems to be, that git thinks that A, and B are already part of master, as they are already in the history. So, it doesn't apply these changes on top of master.

How can I force git to do this?

Lemming
  • 4,085
  • 3
  • 23
  • 36
  • 1
    What exactly do you mean by *I failed to achieve this*? Do you get a particular message from Git? Also, add the exact `rebase` and `cherry-pick` commands you used. – jub0bs Aug 31 '14 at 17:50
  • @Jubobs *Fails* meaning that the changes of `A`, and `B` are not there. It is not an error as far as git is concerned. The rebase command was `git rebase --onto master beforePR B`, where `beforePR` was the last commit before `A`. This is straight from the `git rebase` man-page. The cherry-pick was `git cherry-pick A..B`. – Lemming Aug 31 '14 at 18:09
  • 3
    Someone had commented here to just *revert the revert*. That actually worked very well. Unfortunately, I don't remember the user-name, but if that person would post that as an answer, and nothing magically better comes along, then I would gladly accept it. – Lemming Aug 31 '14 at 18:23
  • 3
    I had a quick look at the [man page](http://git-scm.com/docs/git-cherry-pick). `cherry-pick` has a `--keep-redundant-commits` option. Maybe this works. I would've posted it as an answer but I was unable to replicate your error condition; I was always able to cherry-pick a reverted commit. – musiKk Aug 31 '14 at 20:14
  • @musiKk Very nice! I wasn't aware of that option. I tried it and it is another good solution to my problem. A down-side compared to reverting the revert is that if the PR was only partially reverted then your new PR would contain empty commits. Those you will need to manually remove using `rebase -i`... – Lemming Sep 01 '14 at 09:11

2 Answers2

3

Besides the cherry-pick option, rebase now has a --force-rebase option to generate new commits so that it will ignore the previously reverted merge.

See also: the revert-a-faulty-merge How-To, git rebase --no-ff, and the full git rebase docs.

dahlbyk
  • 75,175
  • 8
  • 100
  • 122
Ari
  • 2,311
  • 1
  • 17
  • 17
  • I have the same problem, but the `--no-ff` and `--force-rebase`/`-f` don't work. Any idea why? – RafazZ Apr 28 '20 at 03:58
0

Edited

git checkout master
git checkout -b redo
git cherry-pick Aref
git cherry-pick Bref
... do fixes and commits
git merge master

Before

* e553928d35646512f640b0f0ca208f6729884993 D
* 5157867afdbdcf4300f7b722e3816e294e0f2ae4 C
* caa01fd5378f87b67811212aa4325963fab72905 Revert "A"
* 8603f6b1231dbefa4911699cb59fa81f1a20e432 Revert "B"
* d4c38c2c63ab0b4be00480bf9c9542ffc66dcb5f B
* f2f6e0a0b7a804a4a8075839d7b73b37b747a7b3 A
* 59597e64b49b234b45a94a86d950f0811a19cdfe root commit

After

* e6a314b66d8be8a85abd6becd53e0d2c7a6332a5 E
* d7d91af4225d5ba7d783303e73bcac1b5ba02a91 B
* 381b95bea7f87662f72a1da67bd70cdfc497be47 A
* e553928d35646512f640b0f0ca208f6729884993 D
* 5157867afdbdcf4300f7b722e3816e294e0f2ae4 C
* caa01fd5378f87b67811212aa4325963fab72905 Revert "A"
* 8603f6b1231dbefa4911699cb59fa81f1a20e432 Revert "B"
* d4c38c2c63ab0b4be00480bf9c9542ffc66dcb5f B
* f2f6e0a0b7a804a4a8075839d7b73b37b747a7b3 A
* 59597e64b49b234b45a94a86d950f0811a19cdfe root commit

Works for me locally

$ git checkout master
Switched to branch 'master'
$ ls
A B C D E
Strikeskids
  • 3,932
  • 13
  • 27
  • 1
    I would agree with this approach if it were contained on one machine. Unfortunately, this will screw the history of `master`. And since `master` is a public branch that is a big no-no. – Lemming Aug 31 '14 at 18:21