Skip to content

Evidence methods guide

Git LFS and Submodule Export Completeness: Review the Tree, Commits, and Large Objects Together

Review a Git export for superproject trees, submodule gitlinks, committed submodule revisions, LFS pointer files, hydrated objects, and reproducible handoff evidence.

A Git checkout can look complete while a submodule is uninitialized or an LFS pointer has no corresponding large object. The superproject tree records a submodule commit, while Git LFS stores a small pointer in Git and the content elsewhere. Start with the exact commit and tree, recurse through every submodule, then match each pointer version, object ID, and size to a hydrated file or an explicit unavailable state. This guide is export guidance, not a clone service, source audit, security review, privacy decision, or permission claim.

Updated

On this page

Freeze the superproject commit and tree

Record the repository identity, exact commit ID, tree ID if available, branch or tag reference, export command, archive digest, and whether the working tree was clean. A folder listing is not a Git tree. Keep tracked files, ignored files, generated files, and untracked files in separate sets so the handoff does not imply that an uncommitted working copy is part of the commit.

The source dates in this guide use 22 October 2026 as retrieval evidence for documentation without a verified publication date. They are not publication claims. Where a verified publication date is available, it is recorded in the source ledger.

Freeze the superproject commit and tree (table)
Tree evidenceRecordStop if
CommitExact object ID and ref usedA moving branch is the only identity
TreeTree path and mode per entryAn export omits a path without explanation
Working treeClean, modified, or unknownLocal edits are mixed into the packet
AttributesRelevant .gitattributes at commitLFS rules come from a local override
Ignore rulesTracked versus ignored stateIgnored files are treated as committed
Export digestDigest and byte scopeArchive is compared by filename only

Use a synthetic repository fixture for a public worksheet. Do not include real source code, private URLs, credentials, or developer names. A commit ID proves which Git object was selected; it does not prove that every external object is available.

Resolve every submodule gitlink recursively

The Git Documentation, (opens in a new tab) page says the superproject tracks a submodule through a gitlink and .gitmodules path mapping. Record submodule path, expected commit ID, URL hint, initialized state, checked out commit, nested submodules, and whether the expected commit is reachable from the supplied repository. The working directory contents cannot replace the gitlink evidence.

Resolve every submodule gitlink recursively (table)
Submodule fieldRecordHold when
Path mappingSuperproject path and .gitmodules nameTwo names resolve to one path
Expected commitGitlink object ID in the treeOnly the current branch is recorded
Checked out commitObserved HEAD and status markerIt differs from the gitlink
Remote hintURL from .gitmodules, not proof of accessURL is missing or rewritten
Nested statusRecursive status for descendantsNested repositories are skipped
ReachabilityCommit exists in the supplied object setClone depth hides the commit

The Git Documentation, (opens in a new tab) documentation describes recursive status and mismatch markers. Keep a missing clone, an uninitialized submodule, a checked out wrong commit, and a dirty submodule as different findings. Do not run commands against an untrusted repository without a controlled environment policy.

Match LFS pointers to hydrated content

The Git LFS, (opens in a new tab) describes a pointer as UTF-8 key and value lines with version first, sorted keys, an OID using a hash method, and a byte size. Record the pointer blob, path, version, OID, declared size, filter rule, hydrated file digest, and observed size. A pointer file in an archive is evidence of an LFS reference, not the large file itself.

Match LFS pointers to hydrated content (table)
LFS evidenceSupportsCannot prove
Pointer versionParser format identifierObject availability
OIDContent identity referenceThat the local file matches it
SizeDeclared content size in bytesThat the export contains those bytes
Filter rulePath expected to use LFSThat every matching path was hydrated
Hydrated digestObserved local content identityServer-side access rights
Pointer extensionExtra metadata to preserveMeaning of an unknown extension

Synthetic LFS ledger

Match LFS pointers to hydrated content code example, JSON
{"path":"assets/fixture.bin","pointer":{"version":"https://git-lfs.github.com/spec/v1","oid":"sha256:fixture-digest","size":"fixture-bytes"},"hydrated":{"state":"not-tested","digest":"not-recorded","size":"not-recorded"},"decision":"hold"}

Reconcile export layers without inflating completeness

Compare the Git tree path set, submodule path set, LFS pointer path set, hydrated content path set, and archive path set. Record exclusions and the command or tool that produced each set. A matching file count is not enough: one missing submodule commit or one unhydrated pointer can change the usable export while the archive still opens.

Reconcile export layers without inflating completeness (table)
ComparisonRecordOpen question
Tree to archiveMissing and extra tracked pathsWere submodule entries expanded or left as gitlinks?
Gitlink to checkoutExpected and observed commitsWas the exact commit fetched?
Pointer to contentOID and size comparisonWas content hydrated or copied as a pointer?
Nested traversalSubmodule descendants and LFS pathsDid a shallow boundary hide objects?
Attributes to pathsRule matches at commitDid export tooling honor filters?
ReproducibilityCommand, version, and digestsCan a reviewer recreate the same packet?

Stop when an external object is unresolved

Stop conditions

  • Stop if the superproject commit, tree, attributes, or export digest is not fixed.
  • Stop if a gitlink commit differs from the checked out submodule or nested status is unknown.
  • Stop if an LFS pointer lacks a matching hydrated object, digest, or declared size comparison.
  • Stop if archive tooling expands or omits submodules without an explicit record.
  • Stop if shallow history, unavailable remotes, or filters make object reachability unknown.
  • Stop before sharing real code or binary content when the report has not been redacted.

Pair this worksheet with the data provenance log for repository and export history and the data card template for collection context. A complete object map does not prove ownership, privacy clearance, or permission.

For a supported non-health collection, after the owner has authority to describe the scope and a controlled metadata packet, the qualified code appraisal request path may be a preparation step. It does not clone repositories, fetch LFS objects, review source code, create a quote, match a buyer, or grant a license.

Sources

  1. Git Documentation: gitsubmodules: Mounting one repository inside another (opens in a new tab)
  2. Git Documentation: git-submodule: Initialize, update or inspect submodules (opens in a new tab)
  3. Git LFS: Git LFS Specification (opens in a new tab)

Use the code appraisal path after the repository export packet is organized.

It does not clone repositories, fetch LFS objects, review source code, create a quote, match a buyer, or grant a license.