Getting started

Prerequisites and build

Install a stable .NET 10 SDK. global.json specifies 10.0.100 with latestFeature roll-forward and disallows prerelease SDKs. Open CODE.Git.slnx in an IDE that supports this solution format, or run these commands from the repository root:

dotnet build CODE.Git.slnx
dotnet test CODE.Git.Client.Tests/CODE.Git.Client.Tests.csproj
dotnet test CODE.Git.Client.IntegrationTests/CODE.Git.Client.IntegrationTests.csproj

The solution contains the library and two console samples. Test projects are separate and must be invoked explicitly. Provider tests skip unless enabled; see Development. Test projects restore xUnit and the Microsoft test SDK; the library has no runtime package references. Building the library also produces its NuGet package and XML API documentation.

Run the sample

dotnet run --project GitClientSample

Program.cs prompts for a URL. Enter uses https://github.com/codeframework/Docs.git. It creates an anonymous client, prints the pinned commit and file tree, then uses CustomFileHandler to print downloaded file metadata. The callback deliberately discards content. It prints result counts and warnings and waits for Enter before exiting. Ctrl+C cancels active acquisition.

The current sample accepts no command-line options and does not save files or configure credentials. Its commented disk-handler example can be adapted for local experiments. See Authentication for authenticated library usage.

For authenticated Azure Repos acquisition to disk, use the separate AzureDevOpsCloneSample, with setup and commands for both Entra tokens and PATs.

Reference the library

From another .NET 10 project, add a reference to CODE.Git.Client/CODE.Git.Client.csproj using its path relative to your project, or consume a package built from that project. The public namespace is CODE.Git.Client.

List and selectively download files

This example belongs in an async application entry point; supply your repository URL and destination:

using CODE.Git.Client;

using var cancellation = new CancellationTokenSource();
using var client = new GitClient(new Uri("https://github.com/example/project.git"));
var tree = await client.GetFileTreeAsync(cancellation.Token);

foreach (var file in tree.EnumerateFiles())
    Console.WriteLine($"{file.Mode} {file.Path} {file.ObjectId}");

var result = await client.CloneAsync(
    new DiskFileHandler(@"C:\Temp\Project"),
    fileTree: tree,
    filter: file => file.Path.EndsWith(".cs", StringComparison.Ordinal),
    cancellationToken: cancellation.Token);

Console.WriteLine($"Processed {result.ProcessedFiles}/{result.SelectedFiles}; complete: {result.IsComplete}");

Listing fetches commit/tree metadata with filter blob:none; file sizes are unknown until downloaded. A supplied tree pins the commit even if remote HEAD changes. Keep the complete tree and select with the predicate; constructing a partial tree fails validation.

Acquire a full snapshot

using CODE.Git.Client;

using var client = new GitClient(new Uri("https://github.com/example/project.git"));
var result = await client.CloneAsync(new DiskFileHandler(@"C:\Temp\Project"));

This path does not require blob filtering, but still requires protocol v2 and shallow fetch support for a nonempty snapshot. It writes snapshot files rather than a .git directory. Full snapshots fail on symlinks, submodules, and LFS pointers unless explicitly configured to skip unsupported content. A failure can leave previously delivered files in the destination.

Process streams without writing a snapshot

using CODE.Git.Client;

using var client = new GitClient(new Uri("https://github.com/example/project.git"));
var handler = new CustomFileHandler(async (file, content, cancellationToken) =>
{
    Console.WriteLine(file.Path);
    await content.CopyToAsync(Stream.Null, cancellationToken);
});
var result = await client.CloneAsync(handler);

Replace Stream.Null with your consumer. Await all work using the stream inside the callback; the client disposes it immediately afterward. See Public API for lifecycle and error contracts.