How to linearize split merge history in Git?
It should be very obvious, but I haven't found a way to do it. Each tutorial describes reloading to the top of an existing branch or a simple interactive rewrite and that's it. Suppose I have a diamond shape like this in git shape:
* 949430f Merge commit (D) (HEAD, mybranch)
|\
| * e6a2e8b (C)
* | 3e653ff (B)
|/
* 9c3641f Base commit (A)
and I want to archive history, for example:
* 949430f Combined commit (BCD)
|
* 9c3641f Base commit (A)
Blocking B and C can be melted or discarded altogether, it doesn't matter, I only want to keep the result. Also I do NOT want to revert commits due to nasty conflicts.
Here's what I've tried:
1) I cannot argue that by simply twisting B and C
git rebase -i HEAD~2
...
p 3e653ff (B)
f e6a2e8b (C)
...
Could not apply a91f3a4
Well, this is somewhat understandable, there are some conflicts.
2) I can't do it by crushing.
git rebase -i -p HEAD~3
...
pick 9c3641f Base commit (A)
f 3e653ff (B)
f e6a2e8b (C)
pick 949430f Merge commit (D)
...
error: unable to match a91f3a4...
3) I can't even drop B and C
git rebase -i -p -m HEAD~3
...
pick 9c3641f Base commit (A)
#pick 3e653ff (B)
#pick e6a2e8b (C)
pick 949430f Merge commit (D)
...
error: Commit 949430f is merged but option -m is not set.
fatal: cherry-pick failed
Could not pick 4f3e6231b5cecf57434613ca3afd2a21ba375eb9
Why? Here is the "-m" option ...
Does anyone know how to fix this problem?
source to share
You want git reset --soft
(plus the commit marked with aragar ). Despite the varying circumstances in the question, see this answer by VonC .
source to share
git rebase -i 9c3641f^ # 1 before base commit
then in the interactive editor
pick 9c3641f Base commit (A)
pick 3e653ff (B)
fixup e6a2e8b (C)
fixup 949430f Merge commit (D) (HEAD, mybranch)
Actually I expected the latter to not be present because the merge compilation disappears during interactive re-registration in my experience.
This will swallow B and C into one commit. D will disappear and you really don't want it, as it doesn't add any code.
This will give you the desired result. The conceptual thing you missed was that you need to keep the first commit (selection), but if you "fix" the other two, they will merge into it. You need to give them something to merge with this, this is not a basic commitment. So, you select the second and then the third merges into it, giving you two commits.
You can also do
git rebase -i 9c3641f
and then simply sees the fixing base in an interactive editor, but pick
and fixup
are the same for the remaining rows.
source to share