I have an existing repository that has root R
, then a few dozens of commits including multiple merges, up to X
, and then linear history up to Y
. I'd like to squash everything from R
to X
into a single commit and force push it. How can I do it without a lot of effort involving re-resolving merges?
Alternatively, this problem could be phrased as changing the root commit from R
to X
and cutting off the graph before X
.
Here is an illustration simplifying the commit graph:
R ---- I want to squash from here...
|
A
|\
B C
| |
D E
| |\
F G H
| |/
I J
|\ \
K L M
|/ |
N /
|/
O
|
X ---- to here.
|
P
|
Q
|
Y
Squashing everything with regular rebase would require re-resolving multiple merge commits. I am aware of git rerere, but I do not know how to use it in this situtation. It was not enabled when commiting all that.
This can be done with rebasing but it's much easier to do by hand
git checkout --orphan temp X
# now you are on a brand new branch with no history, and your working tree is just like X
git commit -m "Single shot"
# now let's carry over X up to Y
git cherry-pick X..Y
If you like the result, set your branch over here and live happily ever after.
Update: If the history after D is complex, it might be better to run a rebase for the last step:
git rebase --rebase-merges X Y --onto temp
And if that history is complex and it includes merges with conflicts, I can offer this script to take care of that last step to avoid having to redo the merges with conflicts: