A git submodule records a dependency as a commit pointer inside your repository, so the superproject commit you tag for a firmware release also names the exact commit of each vendored library. Clone with recursion, update deliberately, and write the pointers into your SBOM.
How the pointer works
Pro Git explains that the superproject tree holds an entry for the submodule path with mode 160000, a commit recorded as a directory entry, plus the commit's SHA-1. The .gitmodules file maps each path to a URL. The submodule's files are not tracked by the superproject at all, only the commit it points at.
Two things follow. A release tag on your repository fixes every library commit at once. And moving a library forward is an ordinary change to the superproject, which you can review.
Getting a clean checkout
A plain clone creates the submodule folder but leaves it empty. Build scripts that assume the folder is populated will either fail or, worse, use a stale local copy.
git clone --recurse-submodules <repo-url>
git submodule update --init --recursive
Use the second line after switching branches or pulling. A pull fetches submodule objects but does not update the working tree unless you ask for recursion.
Updating on purpose
To move to the latest upstream commit, run git submodule update --remote, then git add the path and commit. That changes the recorded pointer, and the pull request shows the old and new commit. Review the upstream changelog for the range, and rebuild before merging.
Publish the library commits before the superproject: git push with the recurse-submodules on-demand option does this, so teammates are not left with a pointer to a commit they cannot fetch.
Turn pointers into inventory
At release time, list each submodule path, URL and pinned commit, and add them to your SBOM along with the upstream version the commit corresponds to. A commit hash alone is hard for a scanner to match to an advisory, so state the release it sits on or the nearest tag.
| Release step | What to capture |
|---|---|
| Tag the firmware | Superproject commit |
| List submodules | Path, URL, pinned commit |
| Map to versions | Nearest upstream release |
| Store | SBOM and tag together |
Where Safeguard fits
Safeguard provides SBOM and dependency scanning, reachability analysis, and policy gates for the source repositories and manifests it supports, and you can run a free scan at gold.safeguard.sh/scan. Check coverage for your build system before relying on it.
Try it yourself
Find a component and see which fields would let you match it to an advisory. A bare commit hash would need a version added.
Click through it at your own pace, or open it full screen.
Quick check
Does a submodule pointer prove the library is unmodified?
It proves which commit you pinned. If someone edits files inside the submodule folder, the working tree can differ from the pointer, so build from clean checkouts.
Can I just copy the library into my repository instead?
You can, but then the version is no longer recorded for you. If you copy, note the source URL, version and checksum next to the code.
Sources
Last reviewed: 19 October 2026.