Join branch into new master commit without merging?

Viewed 49

I have 2 branches: master and mybranch the mybranch is based on an old master commit and I'd like move it to a new master commit without merging into master.

The hierarchy tree currently look like this:

master[commit1]---[commit2]---[commit3]---[commit4]
          |
          |
       mybranch[commit1]---[commit2]

I'd like it to be like this:

master[commit1]---[commit2]---[commit3]---[commit4]
          |                                   |
          |                                   |
       mybranch[commit1]---[commit2]       mybranch[commit3]---[commit4]

Here is a screenshot from Sourcetree:

enter image description here

1 Answers

When trying to understand and manipulate git branch trees, it's important to know that branches are a pointer to the most recent commit in a particular lineage, and history is traced back from there. Older commits don't "belong to" a particular branch, they are just reachable in its history.

So your actual tree looks like this (I've renamed the two commits you called commit1 to commit_1 and commit_b1; this is one of the reasons git commits are referenced by hashes, not sequential IDs!):

           +---[commit_2]---[commit_3]---[commit_4] <-- master
           |
[commit_1]-+
           |
           +-- [commit_b1]---[commit_b2] <-- mybranch

If you redraw the tree you asked for in the same way, it will look like this:

                                           master
                                             |
                                             v
           +---[commit_2]---[commit_3]---[commit_4]---[commit_b3]---[commit_b4] <-- mybranch
           |
[commit_1]-+
           |
           +-- [commit_b1]---[commit_b2] <-- ???

There is no relationship between commits b1 and b2 on one hand, and b3 and b4 on the other. The branch pointer "mybranch" can't point to both of them, unless it points to a new commit that merges them together.

However, that may be what you wanted: you talk about "moving" the branch, which is what git rebase does. More accurately, it copies the commits, creating new commits that look like them, so commit b3 will be a copy of b1 and b4 a copy of b2. (The original b1 and b2 commits, which are now unreachable by any branch pointer, will eventually be garbage collected.)

The most explicit form of git rebase requires you to specify three points in history - usually branch names, but can be anything that identifies a particular commit:

git rebase --onto <new-parent> <old-parent> <branch>

It means "take all the commits from <old-parent> up to and including the current tip of <branch>, recreate them on top of <new-parent>, and point <branch> at the last of these new commits".

In common scenarios, you can specify fewer arguments:

git rebase <parent> <branch>

This means "take all the commits that are reachable from <branch>, but not from <parent>; recreate them on top of the current tip of <parent>, and point <branch> at the result.

git rebase <parent>

This is the same as above, but it uses the currently checked out branch as <branch>.

So in your case, any of the following should produce the same result:

git rebase --onto master commit_1 mybranch
git rebase master mybranch
git switch mybranch; git rebase master
Related