https://medium.com/@porteneuve/mastering-git-subtrees-943d29a798ec
A very good article about subtree, however there's some errors and some out-of-dated commands (git has since then changed). Nevertheless I followed through and the summary below is accurate as of Feb 2021
subtree:
it's just one repo - everything commits to "container" (main difference with submodule)
with subtree, a sub tree of the container can be pulled, pushed with another remote repo (hence sub tree)
everything can be done in either of the following ways:
manually - just some tricks to do things without "subtree"
subtree - it's now an official contrib with default install
with other tools
"plugin" is just the given name of the remote
# step 1, add the remote repo and fetch it (no merging)
git remote add plugin ../remotes/plugin
git fetch plugin
# step 2, read-tree, to put under path specified by --prefix from branch plugin/master
git read-tree --prefix=vendor/plugins/demo -u plugin/master
# step 3, commit
git commit -m "Added demo plugin subtree in vendor/plugins/demo"
git remote add plugin ../remotes/plugin/
git subtree add --prefix=vendor/plugins/demo --squash plugin master
Manually
# Step 1, fetch remote change without doing anything with local repo
git fetch plugin
# Step 2, merge the changes, -X specifies merge strategy, i.e. adjust the dir structure of the merge so incoming change and local would match
git merge -X subtree=vendor/plugins/demo --squash plugin/master --allow-unrelated-histories
git status
git commit -m "Updated the plugin"
git subtree pull --prefix=vendor/plugins/demo --squash plugin master
# Step1, checkout the subtree repo (i.e. plugin/master) and create a branch, prepare to backport
git checkout -b backport-plugin plugin/master
# Step 2, backport by cherry picking specific commits from master
# Here "master^" means the parent of master
# See https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection for more details
# -x meant to add a line in commit message marking the cheey picking
git cherry-pick -x --strategy=subtree master^
# Step 3, push the backport
git push plugin HEAD:master
# Much simpler, but there is not cherry picking, just push all changes
# As long as there is no "container specific" change in the subtree, it does not matter
git subtree push -P vendor/plugins/demo plugin master
Just a plain old git remote
git rm -r vendor/plugins/demo
# Step 1, create a new branch
git checkout -b split-plugin
# Step 2, reduce both commit history and repo directory to a subdirectory
# this filter out commits that only touched the subdirectory, also trims down dir
git filter-branch --subdirectory-filter lib/plugins/myown
# Step 3, examine the reduced down repo, then push to remote
git remote add newsubtree ../remotes/newsubtree
git push -u newsubtree split-plugin:master
# Step 1, use subtree command to split the repo into a branch
git subtree split -P lib/plugins/myown -b split-plugin
# Step 2, checkout the new branch
git checkout split-plugin
# Step 3, push the new branch to remote
git remote add myown ../remotes/myown
git push -u myown split-plugin:master
add back the subtree in container (otherwise --squash would not work)
# Step 1, remove the subtree
git rm -r lib/plugins/myown
git commit -m "Removing lib/plugins/myown for subtree replacement"
# Step 2, add it back
git subtree add -P lib/plugins/myown --squash myown master
# Step 3, check to make sure --squash works
git subtree pull --squash -P lib/plugins/myown myown master