How to subtree merge in Git
Git subtree allows incorporating external repositories into your project as subdirectories without the complexity of submodules. As the creator of CoreUI with over 25 years of version control experience since 2000, I’ve used subtree merging to integrate third-party libraries while maintaining full control over the code. The standard approach adds a remote for the external repository, then uses git subtree to merge it into a specific directory. This provides cleaner workflows than submodules for vendoring dependencies.
Add an external repository to a subdirectory using subtree.
git remote add library https://github.com/username/library.git
git subtree add --prefix=vendor/library library main --squash
The remote add creates a reference to the external repository. The subtree add merges it into the vendor/library directory. The --squash combines all commits into one. The library code becomes part of your repository history.
Pulling Updates from Upstream
Update the subtree with latest changes from the external repository.
git fetch library
git subtree pull --prefix=vendor/library library main --squash
The fetch downloads new commits from the remote. The subtree pull merges updates into the subdirectory. The --squash keeps a clean history. Your repository stays synchronized with upstream.
Pushing Changes Back to Upstream
Contribute modifications back to the original repository.
git subtree push --prefix=vendor/library library feature-branch
The subtree push extracts commits affecting the subdirectory. Only changes in vendor/library are pushed. The upstream repository receives a clean pull request. This enables bidirectional collaboration.
Splitting a Subdirectory into Separate Repository
Extract a subdirectory into its own repository.
git subtree split --prefix=vendor/library -b library-split
git push library library-split:main
The subtree split creates a branch with only commits affecting the directory. The push uploads it to a remote repository. This is useful for extracting shared code into a library.
Managing Multiple Subtrees
Organize several external dependencies as subtrees.
git remote add ui-lib https://github.com/username/ui-lib.git
git subtree add --prefix=vendor/ui-lib ui-lib main --squash
git remote add utils https://github.com/username/utils.git
git subtree add --prefix=vendor/utils utils main --squash
git fetch --all
git subtree pull --prefix=vendor/ui-lib ui-lib main --squash
git subtree pull --prefix=vendor/utils utils main --squash
Each subtree operates independently. The fetch --all updates all remotes. Individual pulls update each subdirectory. This approach works well for vendoring multiple libraries.
Best Practice Note
This is the same subtree workflow we use when vendoring dependencies in CoreUI projects that require full control over third-party code. Subtrees are simpler than submodules - they’re just regular commits, no special clone procedures needed. Use --squash to avoid polluting your history with hundreds of upstream commits. For read-only dependencies, subtree works great. For bidirectional workflows, ensure clear conventions about where changes originate. Document your subtree remotes and prefixes in the README. For modern projects, consider npm packages or Git submodules - subtrees are best when you need the dependency code fully integrated into your repository.



