How to rebase only the commits after the latest merge?

隐身守侯 提交于 2019-12-09 13:48:08

问题


Consider following scenario:

  1. I checked out a branch from master
  2. I made some commits
  3. I merged updated master
  4. I made some more commits
  5. Now I want rebase commits from point 4 so that commits from point 2 are not affected.

So if I have initially:

     (1)         (2)
x--x--x--x--x--x--x         master
       \     \
        y--y--Y--y--y       dev
          (2)(3)   (4)

I want to get:

     (1)         (2)
x--x--x--x--x--x--x             master
       \           \
        y--y--------Y'--y'--y'  dev
          (2)      (5)     (5)

If I just do git rebase master it will rebase commits both from 2 and from 4 and delete merge from 3. It's not what I want.

There is also option to do git merge master, then git rebase -i -p before the merge commit from 3 and move the last merge after the merge from 3 and do fixup/squash it into the merge from 3. Update: it does not work that easy. Git refuses to squash two merges. This problem: git rebase interactive: squash merge commits together .


回答1:


You start from:

     (1)
x--x--x--x--x--x--x         master
       \     \
        y--y--Y--y--y       dev
          (2)(3)   (4)

Do a git rebase --onto:

git branch dev1 Y^
git rebase --onto master Y^ dev

Y^ references the first parent of the merge commit Y: here 'y', and not 'x'.
See "Ancestry References":

The first parent is the branch you were on when you merged, and the second is the commit on the branch that you merged in.

You would end up with:

     (1)
x--x--x--x--x--x--x             master
       \           \
        y--y        Y'--y'--y'  dev
          (2)      (5)
        (dev1)

That would split your initial dev branch in two, and apply only the last dev commits on top of master, while keeping the first dev commits unchanged, now referenced by the branch dev1.

You can try a:

git rebase -p --onto master `Y^` dev

to see if that preserve the relationship between between y (that is Y^) and the newly rebased Y'. But I doubt that is possible.

-p is for --preserve-merge.




回答2:


Using my and VonC's answers made more automate-able solution:

git checkout -b tmp Y
git merge master 
git reset --soft HEAD^^ 
git rev-parse master > .git/MERGE_HEAD 
git commit -C Y
git checkout -
git rebase --onto tmp Y
git branch -d tmp

Y - is the merge commit to be extended.

And it works like this:

x--x--x--x--x--x--x         master
       \     \
        y--y--Y--y--y       dev

x--x--x--x--x--x--x         master
      |      \
       \      Y             tmp
        \    / \
         y--y   y--y        dev

x--x--x--x--x--x--x         master
      |      \     \
       \      Y-----Y'      tmp
        \    / \
         y--y   y--y        dev

x--x--x--x--x--x--x         master
      |            \
      |      -------Y'      tmp
       \    /
        y--y--Y--y--y       dev

x--x--x--x--x--x--x         master
      |            \
      |      -------Y'      tmp
       \    /        \
        y--y          y--y  dev

x--x--x--x--x--x--x           master
       \           \
        y--y--------Y'--y--y  dev



回答3:


I end up doing the following:

git rebase -i -p Y^

In the file add the following line after line with the merge (presumably after the first line):

exec sh -c "git merge master; git reset --soft HEAD^^; git rev-parse master > .git/MERGE_HEAD; git commit -C `git rev-parse HEAD`"


来源:https://stackoverflow.com/questions/18978494/how-to-rebase-only-the-commits-after-the-latest-merge

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!