Skip to main content

Managing External Dependencies with Git Subtrees

Pascal Spörri
Author
Pascal Spörri
Table of Contents
Simplify external code management with Git subtrees.

Git subtrees are a powerful feature that let you integrate another Git repository into your own as a subdirectory. Unlike Git submodules, which maintain a reference to an external repo, subtrees physically embed the other repository’s contents within your own history—making them easier to manage in many cases.

This post explains how to use Git subtrees to add and update external repositories within your project.


What Is a Git Subtree?
#

A Git subtree imports the entire history of an external project into a subdirectory of your repository, usually as a squashed commit (one combined commit, rather than the full log).

This differs from Git submodules, which store only a pointer to a specific commit in another repository. Subtrees are better when:

  • You want to vendor dependencies directly into your repo
  • You want to avoid extra tooling for submodules
  • You want everything under one roof (e.g., for deployment or archiving)

Commands
#

Adding a Git Repository as a Subtree
#

You can add another repository as a subtree like this:

git subtree add --prefix=target_dir git_remote.git branch --squash
  • --prefix=target_dir: Specifies the directory within your repo to place the external project.
  • git_remote.git: URL or path to the external Git repository.
  • branch: The branch to import.
  • --squash: Combines the subtree’s history into a single commit.

This results in a commit that looks like this:

commit f5ddddda7d42d06cd7883f7c495124f7dd4f503f
Merge: ed74e04 688ea1d
Author: Pascal <pascal@localhost>
Date:   Fri Sep 16 12:02:58 2016 +0200

Merge commit '688ea1de2af40776bfda21e59a14f97e6204e294' as 'foo'

commit 688ea1de2af40776bfda21e59a14f97e6204e294
Author: Pascal <pascal@localhost>
Date:   Fri Sep 16 12:02:58 2016 +0200

    Squashed 'target_dir/' content from commit 62372d7

    git-subtree-dir: target_dir
    git-subtree-split: 62372d78da03021a81c12972e483d3d074469be7

Updating a Git Subtree
#

To pull in changes from the upstream project:

git subtree pull --prefix=target_dir git_remote.git branch --squash

This adds a new squashed commit with the updated content.


Further Reading
#

For an in-depth comparison of subtrees vs submodules, see Atlassian’s write-up: 👉 The Power of Git Subtree.