I am currently working on a branch that looks like this
--A------B (master)
/ \
----C--D E--F (feature_branch, HEAD)
I've been trying my best to fix it without success :(
git-rebase <A_SHA1>
doesn't seem to work at all. There are currently only two branches: master
and feature_branch
.
Is there even a way to make it look like this?
--A------B (master)
\ / \
C--D E--F (feature_branch, HEAD)
Note that existing commits cannot be changed, so given:
...--α--A------B <-- master
/ \
....--γ--C--D E--F <-- feature_branch (HEAD)
what you'll inevitably get from a rebase is, instead:
C'-D' E'-F' <-- feature_branch (HEAD)
/ \ /
/___---B'
//
...--α--A------B <-- master
/ \
....--γ--C--D E--F [abandoned]
You can then forcibly move master
to point to B'
instead of B
so that you have:
C'-D' E'-F' <-- feature_branch (HEAD)
/ \ /
/___---B' <-- master
//
...--α--A------B
/ \
....--γ--C--D E--F [abandoned]
It's now possible to ignore the presence of B
, γ
, C
, and so on entirely and pretend that C'
is C
, for instance. Note that commit γ
has become unreachable unless α
and γ
are really the same commit.
To achieve this using git rebase
, you will want the somewhat-newfangled -r
or --rebase-merges
option:
git checkout feature_branch # if needed - you've drawn a detached HEAD
git rebase -i -r --onto master <hash-of-γ>
after which you will need to delete commits such as α
and A
from the list of commits to be pick
-ed, as these commits are all currently on feature_branch
as well as on master
, through merge commit B
. (Note that -r
was new in Git 2.18. The -r
option uses the interactive machinery to instruct Git to re-perform merges, which is what we will do below.)
Overall, though, it's probably easier to achieve this using separate git cherry-pick
and git merge
commands:
git checkout --detach <hash-of-A> # note: master~1 probably finds commit A
git cherry-pick <hash-of-C> # make C'
git cherry-pick <hash-of-D> # make D'
git merge --no-ff <hash-of-A> # make new merge B'
git branch -f master HEAD # forcibly update master now
git cherry-pick feature_branch~2 # make E'
git cherry-pick feature_branch~1 # make F'
git checkout -B feature_branch # forcibly move feature_branch and re-attach HEAD
If master~1
does identify commit A
, you can use that in place of each literal hash here, and in that case, master^2^
will identify commit C
and master^2
will identify commit D
, so you can use that in place of those two literal hash IDs.