Reputation: 1003
I have current branches in a git repo as follow.
_d_e_f__(branch A)
(Master)_a_b_c__/
\_g_h_i__
(branch B)
After, creating a new branch C from A and merging B into C git checkout A && git checkout -b C && git merge B
_d_e_f__(branch A)
(Master)_a_b_c__/ \__________(branch C)
\_g_h_i__/
(branch B)
Now, let say master branch added a new commit and I wanted to rebase all branches (A,B,C) to the new commit in master. What is the proper way of do so? I had tried the following, and everything works fine except when i check the graph, however, the merge from branch B into C does not seem to be integrated after rebase.
git checkout A
git rebase master
git checkout B
git rebase master
git checkout C
git rebase --onto A f
What I can see from the graph is that the a separated commit(m) is create for merging B into C.
_m__C
A___/
master_____/
\B
Upvotes: 1
Views: 1093
Reputation: 488183
TL;DR: Consider using Graphite. I have not used Graphite myself, but read the text below, see if it matches up with your goals, and then see the linked item, which may be an out of the box method of doing this.
You may be able to achieve your goal using (1) the newfangled --rebase-merges
option and (2) subsequent branch-name updates. This depends on your ultimate goal and this goal is not entirely clear to me from your question as it stands at the time I write this answer.
The command sequence for doing this would be:
git checkout branch-C
git rebase --rebase-merges master
git log --graph # to find hash IDs below
git branch -f master <hash1>
git branch -f branch-A <hash2>
git branch -f branch-B <hash3>
where the two hash IDs can only be discovered by running git log
after the git rebase --rebase-merges
finishes.
There are several things to keep in mind here:
Rebase works by copying commits, as if with git cherry-pick
. (The kind of rebase that --rebase-merges
does literally uses git cherry-pick
internally; some others sometimes use alternate commands that may run faster but not work as well for some cases.)
Each copied commit "does the same thing" as each original commit, and re-uses the log message from its original commit, but has a new, different hash ID.
The cherry-pick command cannot copy a merge commit, so the --rebase-merges
option does not even try to do that. Instead, having copied the commits that were inputs to the original merge, the rebase-merges code runs an all-new git merge
command to create the new merge.
Because this is an all-new merge, any special actions taken during the original merge are lost. Previous conflict resolutions are retained if and only if you have git rerere
enabled (this will be the case in upcoming versions of Git, but is not the case in most existing and old versions). Any special flags you used, such as -X ours
or -X theirs
, are lost.
What this means is that we start with, say:
D-----E-----F <-- branch-A
/ \
A--B--C <-- master M--N--O <-- branch-C (HEAD)
\ /
G-----H-----I <-- branch-B
where branch-A points to commit F
, branch-C
points to commit O
, branch-B
points to commit I
, and master
points to commit C
.
We check out branch-C
before starting the rebase, and use --rebase-merges
, so that Git will produce a set of instructions listing the commits to be copied / merged. This set of instructions reads:
C
as a detached-HEAD.D
, E
, and F
.F'
.C
.G
, H
, and I
.I'
.F'
and perform a merge of I'
(to make M'
).N
, O
, and P
.There's an implied final instruction to move the name branch-C
to point to the last commit made here.1 If you add --interactive
to this rebase, you'll see a textual version of the instruction sheet, which Git will allow you to edit. If not, Git just begins working, using the instruction sheet, which it makes and interprets even without --interactive
because the rebase might stop in the middle. If so, you will presumably resume it later, for which it needs these instructions to be saved. (The rebase also keeps a running "what's done and what's next to do", to go with the todo-instructions; the exact mechanism here is up to the rebase code and has changed over time.)
If all goes well, the final result, after all the instructions—including the final and implied "move the branch name" step—have been executed, is this:
D-----E-----F <-- branch-A
/ \
C <-- master M--N--O ???
/ \ /
| G-----H-----I <-- branch-B
/
A--B
\
| D'----E'----F'
\ / \
C' M'-N'-O' <-- branch-C (HEAD)
\ /
G'----H'----I'
That is, this git rebase --rebase-merges
has already done all the copying required, because master
, branch-A
, and branch-B
just need to point to commits C'
, F'
, and I'
after the copying is complete.
Unfortunately, Git itself does not have anything built in to handle all of this. Graphite might.
1It occurred to me while writing this that it would have been better to make this an explicit instruction. This could still be done, in a future Git.
Upvotes: 1