Git rebase "--preserve-merges --onto" does not save merges

Using git v1.7.1 I am trying to reinstall with both --preserve-merges and with --onto at the same time. The final results do not seem to have commits, so they seem linear. I would prefer to keep merge commits for the same reason that people often used --preserve-merges (it would be easier to see a group of commits, which was a logically separate function and was developed in its own branch).

My main branch (destination for reinstallation) is boring:

ABC

The function branch that I want to use has a child branch that has been merged with it. How:

  X - Y / \ VW ------ Z 

Where Z is the merge commit, which is the head of the feature branch, and X and Y are in the auxiliary function branches.

I use: git rebase --preserve-merges --onto CVZ

I would like to end up with:

  X - Y / \ ABCW ------ Z 

But instead, I get:

 ABCWXY 

Since Z is a messy merger, the final state of the code is correct, but the story is not as expressive as we would like.

Is there any way to get what I want?

change @Bombe address : I wrote a bash script to build my example. On my system (RHEL 6.2 with git 1.7.1) this demonstrates my problem.

 #! /bin/bash # start a new empty repo git init # make some commits on the master branch git checkout master touch A.txt; git add A.txt; git commit -m "add A.txt"; git tag Atag touch B.txt; git add B.txt; git commit -m "add B.txt"; git tag Btag touch C.txt; git add C.txt; git commit -m "add C.txt"; git tag Ctag # now build the feature branch # start at Btag (more or less arbitrary; point is it before C) git checkout Btag git checkout -b feature touch V.txt; git add V.txt; git commit -m "add V.txt"; git tag Vtag touch W.txt; git add W.txt; git commit -m "add W.txt"; git tag Wtag # now a subfeature git checkout -b subfeature touch X.txt; git add X.txt; git commit -m "add X.txt"; git tag Xtag touch Y.txt; git add Y.txt; git commit -m "add Y.txt"; git tag Ytag # merge the subfeature into the feature # preserves branch history with --no-ff git checkout feature git merge --no-ff subfeature # the merge commit is our Z git tag Ztag # one more commit so that merge isn't the tip (for better illustration of Z missing later) touch postZ.txt; git add postZ.txt; git commit -m "add postZ.txt"; git tag postZtag # now do the rebase git rebase --preserve-merges --onto Ctag Vtag # optionally move the master branch forward to the top of feature branch git checkout master git merge feature 

Before reinstalling, I get:

  XY / \ VW-----Z-postZ / ABC 

After reinstalling, I get:

  XY / \ VW-----Z-postZ / ABC-W'-X'-Y'-postZ' 

Note the absence of Z 'between Y' and postZ '.

+7
git rebase
source share
3 answers

Many thanks to Bombe and a friend for pointing out that this works for some people. With this inspiration, I can now answer my own question.

Short answer: git versions prior to 1.7.5.2 will exhibit this bad behavior.

Long answer: in git's own source repo, commit c192f9c865dbdae48c0400d717581d34cd315fb8 on April 28, 2011 was clearly a fix for this problem.

To quote a commit message (Andrew Wong):

 git-rebase--interactive.sh: preserve-merges fails on merges created with no-ff 'git rebase' uses 'git merge' to preserve merges (-p). This preserves the original merge commit correctly, except when the original merge commit was created by 'git merge --no-ff'. In this case, 'git rebase' will fail to preserve the merge, because during 'git rebase', 'git merge' will simply fast-forward and skip the commit. For example: B / \ A---M / ---o---O---P---Q If we try to rebase M onto P, we lose the merge commit and this happens: A---B / ---o---O---P---Q To correct this, we simply do a "no fast-forward" on all merge commits when rebasing. Since by the time we decided to do a 'git merge' inside 'git rebase', it means there was a merge originally, so 'git merge' should always create a merge commit regardless of what the merge branches look like. This way, when rebase M onto P from the above example, we get: B / \ A---M / ---o---O---P---Q 

Solution: get a new version of git, coming from the source, if necessary.

Btw, I used git bisect to figure this out. Awesome tool.

+10
source share

I ran into this problem. Pay attention to my git version, this is 1.7.10.2.

I am doing redefinition of the commit range (identified by its SHA1 hashes) on the branch, as well as the absence of the last merge.

My solution was to reinstall W on X to C (without -preserve-merges) and then rebase (from -preserve-merges) Y, Z, and postZ to X '.

Hope this helps.

+1
source share

I just tried to recreate your situation, and I can report that --preserve-merges works as advertised. When youre doing Z, just do:

 git rebase --preserve-merges --onto CV 

Here's what I did, and he retained the merge fix.

0
source share

All Articles