I've researched this on SO and other documentation. I've tried rebasing, merging, cherry-picking, and detached heads.
After literally 6 hours of trying to do this, it's time to ask the question!
Here's what I'm starting with:
A-B-C-D-E-F-G master
Here's what I want to change it to:
A-B F-G master
\ /
C-D-E dev
The closest I've come is:
A-B C-D-E-F-G-H Main
\ /
C-D-E dev
\
F-G master
I had to add another branch name and a dummy commit to get the branching to work at all.
But this is worse than no change.
Please help!
UPDATE AFTER REPLIES
Thanks for the replies.
Yes, my "what I want" was not very clear. Hopefully this clarifies it:
A-B - F-G master
\ /
C-D-E dev
In other words, "master" at F is the result of B plus branch "dev" merged into it.
STILL NOT WORKING
Thanks @frasertweedale for the attempted answer.
I've followed your instructions carefully and here's what I end up with:
A-B - "merge branch 'dev'"-G master
\ /
C-D-E dev
\
F-G-"merge branch 'dev'"-F-G
I'm glad this is hard: having now spent 7 hours on this I don't feel as bad!
FINAL RESULT As @frasertweedale said, this is exactly what I wanted except for the dangling commits.
So, I simply need to get rid of the dangles.
For clarity, I've redrawn below:
A-B - "merge branch 'dev'"-G2 master
\ /
C-D-E dev
\
F1-G1-"merge branch 'dev'"-F2-G2
And this command does the cleanup:
git rebase -p --onto F1^ F1
Result:
A-B - "merge branch 'dev'"-G2 master
\ /
C-D-E dev
"merge branch 'dev'" contains the original F commit, and can, of course, be re-commented that way.
Assuming you expand
A
,B
, etc into their corresponding commit hashes, and thatmaster
is atG
, the first step is to branchdev
atE
:Then reset
master
toB
.Next, merge
dev
intomaster
, explicitly demanding a merge commit (it will otherwise do a fast-forward sincedev
has not diverged frommaster
):master
now contains commits up toE
. Now you can cherry-pick the originalF
andG
commits.Now you have something very close to what you wanted; the only difference is the addition of a merge commit
(B+E)
:If you now want to include the content of
F
in the merge commit(B+E)
, you can perform an interactive rebase and squash the two commits together. The--preserve-merges
(alias-p
) option is essential.This will invoke an editor with content similar to the following (commit hashes and summaries will differ):
Replace the
pick
directive at the start of theF
commit line with thesquash
directive (in the above example:squash 61552ad f
), then save and exit. You will be prompted to form a new commit message from the commit messages of the merge commit andF
, and the rebase operation will then complete without further interation. After the rebase, you will have exactly the repository history you asked for (in your updated question).ABBREVIATED SCRIPT
The following script creates a new repository with a linear history, then automatically edits the history using (mostly) the same steps as above. The interactive rebase is avoided so that user intervention is not required.