Clone an authenticated Azure DevOps repository

AzureDevOpsCloneSample demonstrates authenticated snapshot acquisition to disk using the existing library. It accepts Microsoft Entra Bearer tokens or personal access tokens (PATs), reads secrets from environment variables, and does not require Git or a credential manager. Azure CLI is only needed if you choose the token-acquisition command below.

What you need

Option 1: Microsoft Entra access token

Sign in with Azure CLI as the identity that has repository access, then request a token for the Azure DevOps resource. The sample sends it with BearerGitCredentials. These commands use PowerShell:

az login
# If needed, choose your organization's tenant with az login --tenant <tenant-id>.
$env:AZURE_DEVOPS_ACCESS_TOKEN = az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken --output tsv
if ($LASTEXITCODE -ne 0) { throw 'Azure DevOps token acquisition failed.' }

try {
    dotnet run --project AzureDevOpsCloneSample -- 'https://dev.azure.com/your-org/your-project/_git/your-repo' '.\azure-snapshot'
}
finally {
    Remove-Item Env:AZURE_DEVOPS_ACCESS_TOKEN -ErrorAction SilentlyContinue
}

Ensure AZURE_DEVOPS_PAT is unset for this mode. Microsoft documents this resource ID and Bearer Git authentication in its authentication overview. The sample does not acquire or refresh tokens itself; rerun acquisition when a token expires. Production applications can integrate their own token provider through IGitCredentials.

Option 2: Personal access token

In Azure DevOps, open User settings > Personal access tokens > New Token. Select your organization, an expiration, and only Code > Read. Copy the PAT to your secret store. PAT creation and scope availability depend on organization policy; see Microsoft's PAT instructions.

For a local trial in PowerShell 7, prompt without echoing the token or putting its literal value in command history:

$env:AZURE_DEVOPS_PAT = Read-Host 'Azure DevOps PAT' -MaskInput
try {
    dotnet run --project AzureDevOpsCloneSample -- 'https://dev.azure.com/your-org/your-project/_git/your-repo' '.\azure-snapshot'
}
finally {
    Remove-Item Env:AZURE_DEVOPS_PAT -ErrorAction SilentlyContinue
}

Ensure AZURE_DEVOPS_ACCESS_TOKEN is unset for this mode. The sample uses new BasicGitCredentials("git", pat); git is a nonempty placeholder username and the PAT is the password. Do not use your normal Microsoft account password, put tokens in URLs/arguments, or commit them. Neither mode uses credentials saved by Visual Studio or Git Credential Manager.

Core library call

The sample supplies credentials and calls full cloning directly:

using CODE.Git.Client;

var pat = Environment.GetEnvironmentVariable("AZURE_DEVOPS_PAT")
    ?? throw new InvalidOperationException("Set AZURE_DEVOPS_PAT before running.");
using var client = new GitClient(
    new Uri("https://dev.azure.com/your-org/your-project/_git/your-repo"),
    credentials: new BasicGitCredentials("git", pat));
var result = await client.CloneAsync(new DiskFileHandler(@"C:\Temp\AzureSnapshot"));

For an Entra token, replace the credentials with new BearerGitCredentials(accessToken). This acquires HEAD's snapshot files, without a .git directory or history. The current API does not accept a branch name for initial acquisition. It preserves executable metadata but does not apply Unix executable permissions.

Compatibility and troubleshooting

This example deliberately omits GetFileTreeAsync and a selection predicate. It therefore avoids the blob-filter and selective unadvertised-OID requirements of listing/filtering, while still requiring protocol v2, SHA-1 objects, and shallow-fetch support for nonempty snapshots. Azure DevOps endpoint compatibility has not been established by a private live run here; successful authentication alone is insufficient. Unsupported servers fail explicitly; no alternative protocol or REST fallback is built in.

HTTP 401 usually indicates a rejected/expired token; 403 indicates forbidden access; 404 may conceal a private repository or indicate a wrong URL. Redirect errors require the final trusted URL. Confirm the token audience (Entra), organization/scope (PAT), and identity's repository permissions. See Authentication for transport boundaries.

LFS pointers, symlinks, and submodules fail by default. Exceptions or cancellation can leave earlier files written; output is not transactional. The sample retains the default public-network policy, so private Azure DevOps Server hosts require an intentional trusted-host configuration in application code. See Security and limits.

The sample returns 0 for a complete result, 1 for usage/configuration or handled acquisition failure, and 2 for caller cancellation. Unexpected errors remain visible. Ctrl+C cancels; there is no final interactive pause.