#28650·argo-cd

feat(repo-server): add opt-in optimized ls-remote mode for large repositories

Author: kirillbilchenkoCreated Jul 9, 2026Updated Sep 16, 2026
Labelsenhancementtriage/pending

Summary

Add an opt-in repo-server mode to optimize Git revision resolution for large repositories by using native Git with protocol v2 server-side ref narrowing where possible.

Example setting:

yaml
reposerver.git.lsremote.optimized.enabled: "false"

The optimization is disabled by default, so existing behavior does not change unless an operator enables it.

Related discussion: https://github.com/argoproj/argo-cd/pull/26429#discussion_r3542404499

Motivation

In large monorepos, git ls-remote can advertise hundreds of thousands of refs. In our repository, the advertised ref set is roughly 800k entries, including many pull-request refs that are not used by normal Argo CD Applications.

Argo CD currently resolves revisions through go-git by listing remote refs. For large repositories, this can be slow and resource-intensive even when Applications only target branches, tags, semantic tag ranges, HEAD, or commit SHAs.

Using native Git with protocol v2 and branch/tag narrowing is much faster for this case:

bash
git -c protocol.version=2 ls-remote --heads --tags <repository>

In our environment, this is around 100 times faster because protocol v2 servers do not need to advertise unrelated refs such as pull-request refs.

Proposal

Introduce a disabled-by-default repo-server feature flag for optimized revision resolution:

yaml
reposerver.git.lsremote.optimized.enabled: "true"

The equivalent repo-server flag is:

bash
argocd-repo-server --git-ls-remote-optimized

When enabled, Argo CD should resolve branches, tags, semantic tag ranges, and HEAD through one shared optimized cache entry.

For each cache refresh, one cache-lock owner should:

  1. Retrieve branches and tags using:

    bash
    git -c protocol.version=2 ls-remote --heads --tags <repository>
  2. Resolve HEAD with a targeted protocol v2 dry-run fetch from a temporary bare repository:

    bash
    git -c protocol.version=2 fetch --dry-run --porcelain --no-tags --depth=1 --filter=tree:0 <repository> HEAD

The targeted fetch uses a bounded set of HEAD-related ref prefixes. --dry-run prevents Git from updating local refs, but it still negotiates and transfers a pack. --depth=1 limits fetched history, while --filter=tree:0 omits trees and blobs when the server supports partial clone filtering. If filtering is unsupported, Git may transfer the complete tip tree.

Both results should be stored together in the same cache entry. Concurrent requests should share this cache fill, producing one branch/tag query and one HEAD query per refresh instead of additional HEAD queries for every caller. Cache hits should not make remote requests.

Full commit SHAs should continue to resolve without a network request.

Existing behavior should remain the default. If either optimized native Git query fails, Argo CD should use the current go-git resolver as the final fallback.

Unsupported fully qualified namespaces, such as refs/pull/123/head, refs/merge-requests/123/head, and other custom refs outside refs/heads/ and refs/tags/, should continue to use go-git directly to preserve compatibility. Short names that cannot be resolved from the optimized branch/tag snapshot should also fall back to the existing resolver.