Suppose we have the following revision graph:
A-B (master)
\
C (feature-a)
\
D (feature-b) [depends on feature a]
\
E (feature-c) [depends on feature b]
And master is then modified to follow with commit F
. Is there any simple way to rebase E
onto F
(master) so that branches feature-a
, feature-b
and feature-c
all end up as follows:
A-B-F (master)
\
C' (feature-a)
\
D' (feature-b)
\
E' (feature-c)
?
In real world situations there are obviously multiple patches between each feature so re-attaching branches in-between manually to rebased history is tedious and error prone job. I know that I can rebase E
to E'
with a simple git checkout feature-c && git rebase master
but that leaves branches feature-a
and feature-b
pointing to commits C
and D
instead of C'
and D'
. Rebase should have all the info to move all the branches, right?
There's nothing built in to git to do this, but it's certainly script-able.
What you need to do is:
feature-a
, feature-b
, and feature-c
).X
is a predecessor of Y
if Y
is a descendent of the X
(and choose something here to handle/break-ties-with two branch names that identify the same commit). In this case, feature-a
is a predecessor of both feature-b
and feature-c
, while feature-b
is a predecessor of feature-c
(only). Save the "distance back" values for predecessors (how far to chase parent chain).feature-c
):
(That's it, all done.)
Predecessor testing is easy with git merge-base --is-ancestor
(pairwise) or git branch --contains
(en masse, but requires filtering away non-rebased branches). Finding the "N back" value is a little trickier, but I believe can be done with git rev-list
piped to wc -l
, for instance.
Edit: I see that the linked answer (in comment above) uses a similar algorithm—including topo-sort/cyclicality-checking, needed because the branch selection method is not "take from commit DAG"—but with more work, explicitly rebasing each branch as directed. If you work from the DAG, the leaf rebase has done all the work, and the predecessors can simply be relabeled, as I noted.
Try this:
git checkout featurea
git rebase
git branch --contains (sha1 of your old commit C) |xargs -n 1 git rebase --onto (sha1 of your new commit C') (sha1 of your old commit C)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With