Safeguard
Developer Tools•

Git subtree or a plain copy: how should you vendor open source code?

Subtree keeps upstream history and a path to pull updates. A plain copy loses both. Compare the two for patching, tracking and security review.

Safeguard Security Team
4 min read

Use git subtree when you want vendored code to keep a link to its upstream, so you can pull updates and see changes. Use a plain copy only for tiny, rarely changing files where you record the origin by hand. A plain copy has no built in way to tell you it is out of date.

What each approach is

Plain copy. You download a release or copy files into a directory and commit them. From Git's view they are your files.

Git subtree. The Git subtree documentation says subtrees allow subprojects to be included within a subdirectory of the main project, optionally including the subproject's history. The add command imports the subproject, and the pull and merge commands bring in later changes. By default the subproject's history joins yours. With the squash option you import only a single commit from the subproject rather than its whole history.

git subtree add --prefix=third_party/examplelib https://github.com/example/examplelib.git v1.4.2 --squash
git subtree pull --prefix=third_party/examplelib https://github.com/example/examplelib.git v1.5.0 --squash

What matters for security

QuestionPlain copySubtree
Can you see what version it isOnly if you wrote it downThe import commit records the source and ref
Can you diff against upstreamManual download and compareFetch and diff
Can you updateManual replaceOne pull command
Do scanners see itOften not, no manifestOften not, still no manifest
Can you carry local patchesYes, but invisibleYes, as commits you can list
Clone sizeSmallLarger without the squash option

The scanner row is the same for both, and it is the key danger. Neither approach creates a package manifest, so tools that read manifests may never see the code. See vendored code and submodule scanning blind spots.

Making either one auditable

  1. Put the code in a clearly named directory such as third_party.
  2. Add a short provenance file beside it. See what to record in a vendored code provenance file.
  3. Keep your local edits in separate commits with clear messages, so the diff against upstream is readable.
  4. Add the component to your SBOM by hand or with a tool that scans for copied code. See copied code and your SBOM.
  5. Include third_party in security scans, not only in license checks. Many setups exclude it by default.

When a plain copy is fine

A single small file with a permissive license, copied once, with a header comment naming the source and version, is reasonable. Anything with a release cycle, a security history or local patches deserves subtree or a proper dependency.

When neither is right

If you copy only to avoid network access at build time, a mirror or a lockfile with a vendor directory may suit you better. See vendoring or using a proxy.

Where Safeguard fits

Safeguard's SBOM and dependency scanning is the layer to check that your vendored directories are visible in your inventory. Try a free scan at gold.safeguard.sh/scan.

Try it yourself

Click through it at your own pace, or open it full screen. Compare what appears in an inventory built from manifests with what a vendored directory would add.

Quick check

Does subtree make vendored code visible to scanners?

Not by itself. Subtree improves tracking in Git, but it creates no package manifest, so record the component in your SBOM separately.

What does the squash option do?

It imports a single commit from the subproject instead of its full history, which keeps your repository smaller.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.