I have a monorepo project proj
using subtrees in a folder sub
under proj/sub
. I have made tons of commits that touch both proj
and sub
. How do I publish the relevant changes to upstream sub
effectively?
Usually, I'd have to cherry-pick every commit using
git cherry-pick -x --strategy=subtree -Xsubtree=sub/ commit-ref
but I have made zillions of commits so this is unfeasible. How can I integrate the changes to sub
at once? For instance, create one big squashed commit that would bring sub
to the same state it is in my monorepo.
Related: View commits that make changes to subfolder, How to cherry pick a range of commits and merge into another branch
A few rebases with a couple of cherrypicks will do, but so far I haven't found an automated way using a single command. Use
git rebase -s subtree -Xsubtree=sub --onto sub_master proj_ini proj_end
to copy onto the subproject master branch sub_master
all toplevel proj
commits from ref proj_ini
(exclusive) to ref proj_end
(inclusive). The branch where you are at doesn't matter. For each commit, these things may occur:
Commits that touch only the subproject sub
will be copied cleanly
Commits that touch only files outside sub
will not show up. Since we are rebasing, these are silently ignored. If you would cherry-pick this
type of commit, an error will occur telling that empty commits are not
allowed (future Git versions may have git cherry-pick --skip-empty
)
Commits that have changes to both sub
and outside it will be
copied with the exact same message, but with only the relevant changes/files kept, the rest being cleanly ignored
Renames/moves from proj
to sub
are cleanly rewritten as creations
Merge commits are mostly cleanly accounted for, with some exceptions
5.1 Explicitly ignore the latest merge commit you did to the proj
master coming from sub
.
5.2 Explicitly merge certain merge commits that had involved conflict resolution, using a cherrypick (current branch must be sub_master
):
git cherry-pick -x --strategy=subtree -Xsubtree=sub -m 2 merge_ref
where -m
is usually 1 or 2 for each parent. (In practice I will blindly try either one and git cherry-pick --abort
and try the other if I get conflicts or unwanted changes)