What I have:
---A----B-----C-----D--------*-----E-------> (master)
\\ /
1----2 (foo)
So I use
rebase -i f0e0796
and remove B5ccb371
and and Ca46df1c
, correct? If I interpret the result correctly, this is whatgitk
shows me for my repo, althoughgit branches
still lists the second branch....A---1---2---E master
Can anyone tell me what happened here?
That's what it's built to do: produce a merge-free linear history from a single tip to a single base, preserving all the parts that might still need a mergeback to the new base.
The rebase docs could be clearer about this: "commits which are clean cherry-picks (as determined by git log --cherry-mark …) are always dropped." is mentioned only as an aside in an option for how to treat empty commits, and "by default, a rebase will simply drop merge commits from the todo list, and put the rebased commits into a single, linear branch." is only mentioned farther along, in the description of another option. But that's what it's for, to automate the tedious identification and elimination of already-applied fixes and noise merges from an otherwise-straightforward cherry-pick.
Is git rebase the feature I am looking for my problem?
Not really. The --rebase-merges
option is being beefed up, and Inigo's answer works well for your specific case, but see the warnings in its docs: it has real limitations and caveats. As Inigo's answer points out, "[t]hese steps assume the exact repo you show in your question", and "git rebase
just automates a series of steps that you can just as well do manually". The reason for this answer is, for one-off work it's generally better to just do it.
Rebase was built to automate a workflow where you have a branch you're merging from or otherwise keeping in sync with during development, and at least for the final mergeback (and maybe a few times before that) you want to clean up your history.
It's handy for lots of other uses (notably carrying patches), but again: it's not a cure-all. You need lots of hammers. Many of them can be stretched to serve in a pinch, and I'm a big fan of "whatever works", but I think that's best for people who are already very well acquainted with their tools.
What you want isn't to produce a single, clean linear history, you want something different.
The general way to do it with familiar tools is easy, starting from your demo script it'd be
git checkout :/A; git cherry-pick :/D :/1 :/2; git branch -f foo
git checkout foo^{/D}; git merge foo; git cherry-pick :/E; git branch -f master
and you're done.
Yes, you could get git rebase -ir
to set this up for you, but when I looked at the pick list that produces, editing in the right instructions did not seem simpler or easier than the above sequence. There's figuring out what exact result you want, and figuring out how to get git rebase -ir
to do it for you, and there's just doing it.
git rebase -r --onto :/A :/C master
git branch -f foo :/2
is the "whatever works" answer I'd probably use for, as Inigo says "the exact repo you show in your question". See the git help revisions docs for the message-search syntax.