Architecture

Component overview

CODE Git solution architecture Applications and both console samples call GitClient. Within the library, GitSnapshotAcquirer coordinates the protocol, HTTPS transport, pack reader, object store, tree parser, and sequential file delivery. Credentials and options configure the pipeline. Git servers and local storage sit outside the library. Unit tests, provider tests, and documentation support the solution. CODE Git · component architecture Managed .NET 10 · read-only HTTPS snapshots · no Git executable Host applications GitClientSample · AzureDevOpsCloneSample · consuming applications CODE.Git.Client GitClient Public API · operation serialization · lifetime Configuration and credentials GitClientOptions · IGitCredentials BasicGitCredentials / BearerGitCredentials GitSnapshotAcquirer Discovery · commit pinning · selection Coordinates metadata, blob acquisition, and delivery Public snapshot models GitFileTree · GitDirectory · GitEntry GitFile · GitFileMode · GitCloneResult Protocol and network GitProtocolV2Client → GitHttpTransport GitPktLineReaderWriter · GitNetworkPolicy Protocol framing · HTTPS · credentials · DNS policy Owned HttpClient, or a trusted caller-owned HttpClient Objects and metadata GitPackReader → GitObjectStore GitTreeParser reads validated objects Pack checksums · SHA-1 identities · delta reconstruction Per-operation budgets and temporary storage Sequential delivery through IFileHandler DiskFileHandler · CustomFileHandler · application implementations Consume streams inside callbacks; the client disposes them afterward Remote Git server Azure Repos / GitHub / GitLab · capabilities required Local resources and application consumers Temporary files · destination folder · custom processing Supporting projects and documentation CODE.Git.Client.Tests · CODE.Git.Client.IntegrationTests · Docs

The arrows summarize calls and data flow rather than every class dependency. All acquisition is coordinated by GitSnapshotAcquirer; the object pipeline validates downloaded data before delivery. Credentials apply in the HTTP transport, and GitClientOptions governs network policy and operation budgets. Temporary files are owned by GitObjectStore; final output belongs to the selected handler. Tests and documentation support the solution and are not runtime dependencies. Open the full-size SVG to inspect or edit the vector diagram.

Project map

Location Responsibility
CODE.Git.Client Public library, targeting net10.0, nullable enabled, XML docs, warnings as errors, package generated on build
GitClientSample Interactive console application demonstrating listing and custom stream handling
AzureDevOpsCloneSample Authenticated full snapshot to disk using an Entra access token or PAT
CODE.Git.Client.Tests Deterministic protocol, pack, tree, acquisition, limits, authentication, and safety tests
CODE.Git.Client.IntegrationTests Opt-in real provider tests, optionally using Basic credentials
Docs Developer and AI documentation included in the solution

The test projects exist in the repository but are not project entries in CODE.Git.slnx.

Implementation map

All internal files below are in CODE.Git.Client/Internal.

Component Responsibility
GitClient (public) Validates options/URL, owns transport, serializes operations with a semaphore, and exposes listing/cloning
GitSnapshotAcquirer Coordinates discovery, HEAD resolution, metadata acquisition, selection, supplied-tree validation, and callbacks
GitHttpTransport Builds GET/POST requests, applies credentials, enforces timeout/retry/redirect policy, and counts response bytes
GitNetworkPolicy Canonicalizes repository URLs and checks DNS addresses against public-network policy
GitProtocolV2Client Discovers capabilities; implements ls-refs, shallow fetch, tree filtering, selective OID requests, and sideband processing
GitPktLineReaderWriter Reads Git packet framing and constructs protocol requests
GitPackReader Validates PACK versions/checksums, inflates objects, reconstructs OFS/REF deltas, and registers objects
GitObjectStore Stores objects in per-operation temporary files, verifies SHA-1 identities, and accounts for resource budgets
GitTreeParser Resolves commit/tree objects into validated immutable directory and file models
DiskFileHandler / CustomFileHandler (public) Writes files safely or delegates processing to application code

Listing flow

  1. GitClient.GetFileTreeAsync acquires the operation semaphore.
  2. The acquirer creates a disposable object store and protocol client.
  3. Discovery GETs info/refs?service=git-upload-pack with Git-Protocol: version=2.
  4. ls-refs POSTs to git-upload-pack to resolve HEAD and its symbolic reference, when available.
  5. A nonempty HEAD is fetched with deepen 1 and filter blob:none.
  6. Pack parsing and tree validation produce GitFileTree. Temporary objects are removed when the store is disposed.

An empty/unborn repository returns an empty commit ID and empty root. Detached HEAD has a null reference name. A tree retains metadata, not downloaded blob streams or a reusable object cache.

Clone flow

The diagram below shows how commit selection and full or selective acquisition combine for a nonempty repository. Network calls pass through the protocol and HTTP layers; pack responses are parsed into the temporary object store before the acquirer builds a tree or delivers files.

CODE Git clone flow Discover server capabilities. Resolve HEAD or use the supplied tree's pinned commit. Fetch a full snapshot or blob-free metadata. Parse and validate the tree and select files. For selective clones, fetch selected blob IDs in batches. Verify selected objects, deliver file streams sequentially, then clean temporary storage and return the result. Errors stop processing and can leave earlier output in place. Clone flow One serialized operation · one pinned snapshot · sequential file callbacks Discover Git protocol v2 capabilities HTTPS transport applies credentials, network policy, and request limits No supplied tree Resolve HEAD once with ls-refs Supplied tree Validate repository and pin supplied commit Do not resolve HEAD again Fetch the pinned shallow snapshot Use deepen 1 for a nonempty commit Full clone: null filter Acquire commit, trees, and blobs No separate selected-blob request Selective clone: nonnull filter Acquire metadata with filter blob:none Defer blob acquisition until after selection Parse tree, validate supplied metadata, and select files When present, evaluate the predicate once per regular/executable file Selective clones with selected files only Fetch distinct selected blob IDs in bounded batches Otherwise skip this step Verify all selected objects are blobs Complete this check before the first callback Deliver each selected file sequentially Open stream → check LFS signature → await IFileHandler → close stream No selected files means no callbacks. Callback side effects are never retried. Clean temporary storage and return GitCloneResult Empty/unborn trees skip commit fetching and file delivery Errors and cancellation stop the flow and clean temporary storage. Previously delivered output remains. The complete snapshot is not transactional.

Open the full-size clone-flow SVG to inspect or edit the vector diagram. The diagram shows successful delivery of supported files. Empty/unborn trees skip commit fetching. No selected files means no callbacks or selective blob fetch. Errors and cancellation stop the flow and clean temporary storage; previously delivered output remains. See Security and limits for unsupported content and Public API for stream ownership and errors.

Without a supplied tree, a full clone fetches the shallow snapshot including blobs; a filtered clone first fetches tree metadata. With a supplied tree, its canonical repository must match, and metadata is reacquired at its commit to validate paths, modes, names, and object IDs. HEAD is not resolved again in that path.

For a selective clone, the predicate runs exactly once per regular/executable file. Selected distinct blob IDs are fetched in batches controlled by BlobBatchSize. No selection means no blob fetch or callback. Unexpected unrelated blobs are rejected. There is no automatic full-download fallback if the server refuses selected blob IDs.

All selected objects are checked to be blobs before callbacks begin. LFS pointer detection occurs as files are processed. Each callback receives a file with known size and a temporary-file stream. Calls are sequential; streams close immediately after each callback. Handler failures stop the operation and are wrapped with the repository path, while cancellation propagates. Earlier output is retained.

Lifetime and protocol boundaries

Each operation has its own budgets and temporary store. Operations on a client serialize; callbacks are not parallel. Dispose a client only after its operation finishes. An internally created HttpClient is owned by the library; an injected one is owned by the caller.

Only HTTPS, protocol v2, and SHA-1 repositories are supported. The client requests no thin packs. Listing/selective metadata acquisition needs filter support; nonempty snapshots need shallow support. Provider capability advertisement and willingness to serve reachable unadvertised blob IDs are independent requirements.

The library has no Git executable dependency, native dependency, REST adapter, persistent repository, history API, staging, push, hook execution, or checkout filter execution. See Security and limits for the trust model and explicit omissions.