5

Is there any way to automatically rebase a large number of merge commits? The answers to another question, Rebasing a Git merge commit suggest using --preserve-merges, but that will also rebase the non-merge commits.

This behavior is not desired when merging feature branches into master or an integration branch, and then discovering that someone else has just pushed changes. Additionally, it is useful to be able to rebase a development branch onto a new master commit, or to remove fixes from development that are not going to be used.

For instance, given the following situation:

* 7909b1a (origin/master) Merge bug/456
|\
| * f9d43b6 (origin/bug/456) 456 - Change color
|/
| * 32666f3 (HEAD, master) Merge branch 'bug/123'
| |\
|/ /
| * 0939652 (origin/bug/123, bug/123) 123 - Fix Spelling
|/
o 96c9aa9 (tag: v1.1.1)

If I run git rebase --preserve-merges origin/master, the the following will result:

* (HEAD, master) Merge branch 'bug/123'
|\
| * 8e6ccbe 123 - Fix Spelling
|/
* 7909b1a (origin/master) Merge bug/456
|\
| * f9d43b6 (origin/bug/456) 456 - Change color
|/
| * 32666f3 (ORIG_HEAD) Merge branch 'bug/123'
| |\
|/ /
| * 0939652 (origin/bug/123, bug/123) 123 - Fix Spelling
|/
o 96c9aa9 (tag: v1.1.1)

This is not desirable, because commit 0939652 is being redone, but it is already pushed to public repos, so it should not need to be replayed. The result I want is the following:

* 710c5d7 (HEAD, master) Merge branch 'bug/123'
|\
| * 0939652 (origin/bug/123, bug/123) 123 - Fix Spelling
* |   7909b1a (origin/master) Merge bug/456
|\ \
| |/
|/|
| * f9d43b6 (origin/bug/456) 456 - Change color
|/
o 96c9aa9 (tag: v1.1.1)

I can manually reset --hard to origin/master, and then re-merge the branches that I already did (using the --rerere-autoupdate option, so that I do not have to reresolve conflicts), but that can get quite complicated when there are 15 merges instead of 1.

Is there any built-in Git solution, or a script that can accomplish what I want?

BTW, doing git rebase -ip master, and then not picking the non-merge commits does not work. I get

error: Commit 00... is a merge but no -m option was given.
fatal: cherry-pick failed
Could not pick 00...
Community
  • 1
  • 1
Joseph K. Strauss
  • 4,683
  • 1
  • 23
  • 40

1 Answers1

-1

Yes, you can get this result by redoing the un-pushed merge with the correct parents.

git checkout -B master origin/master
git merge bug/123

and deal with any conflicts the same way as for the 32666 merge. Since the rebase didn't produce any remarkable number of conflicts, the merge won't either.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • I already mentioned that possibility, "I can manually reset --hard to origin/master, and then re-merge that branches that I already did (using the --rerere-autoupdate option, so that I do not have to reresolve conflicts), but that can get quite complicated when there are 15 merges instead of 1." – Joseph K. Strauss Jul 28 '15 at 21:19
  • Please draw an accurate commit graph reflecting what you want. What you have now as your desired result, the commit graph you drew, is exactly the merge you say you don't want, and wanting to not have to reresolve conflicts you already resolved in an existing merge is just another way of saying you want to **re**use **re**corded **re**sults. – jthill Jul 28 '15 at 21:43
  • The graph is accurate. I just want a solution that is practical for a large number of merges. To quote the original question, "that can get quite complicated when there are 15 merges instead of 1". I will try to make that clearer. – Joseph K. Strauss Jul 29 '15 at 15:14
  • If git's built-in automerge doesn't do it for you automatically, I think it's a good bet anything that does do it automatically is going to produce bad merges intolerably often. I don't think there are any shortcuts when you want to do fifteen separate merges. Perhaps if you provide some concrete example of the complications you suspect might not be inherent, complications that could perhaps be avoided with a little extra work, it would help. – jthill Jul 29 '15 at 16:25
  • I think you are misunderstanding. The rerere process works just fine. I want to automatically call `git merge` on all branches the I merged that the other person did not merge. – Joseph K. Strauss Jul 29 '15 at 18:19
  • So the problem is identifying unmerged branches? [Then you want this answer](http://stackoverflow.com/questions/12276001/git-finding-unmerged-branches). (from [this google](https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#newwindow=1&q=git+find+unmerged+branches)). – jthill Jul 29 '15 at 20:09
  • That is kind of what I have been doing, but there are a number of problems, such as if the branch has progressed, but I do not want to merge the new HEAD, or if the branch has been deleted because it was not necessary, but if I leave it out, I will lose that merge. – Joseph K. Strauss Jul 30 '15 at 00:41
  • These are the kind of details that would have been very helpful in your question. What's asked for currently won't help with the situation you're facing. If you'll update the q and describe what you're doing now and concrete details like this about what's prompting you to ask for help, it'll be very much easier to do. – jthill Jul 30 '15 at 00:50