Skip to content

speed up av sync on repos with many remote refs - #766

Merged
aviator-app[bot] merged 2 commits into
masterfrom
sync-perf-large-repos
Jul 8, 2026
Merged

aviator-app[bot] merged 2 commits into
masterfrom
sync-perf-large-repos

Conversation

@tulioz

@tulioz tulioz commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

on large github repos the unfiltered ls-remote (365k+ refs on one customer repo) and the 10k-commit go-git trunk walk make even no-op syncs take ~30s+

@aviator-app

aviator-app Bot commented Jul 2, 2026 •

Copy link
Copy Markdown
Contributor

Current Aviator status

Aviator will automatically update this comment as the status of the PR changes.
Comment /aviator refresh to force Aviator to re-examine your PR (or learn about other /aviator commands).

This PR was merged using Aviator (commit d8ac806).


See the real-time status of this PR on the Aviator webapp.
Use the Aviator Chrome Extension to see the status of your PR within GitHub.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the process of fetching and pruning merged branches. It replaces the broad ls-remote call with targeted fetching of individual PR refs, restricts the commit history traversal range when searching for merge commits by finding the fork point, and extends PR close-pattern matching to include commit subjects. The reviewer feedback highlights two important issues: first, git merge-base --octopus can return multiple merge bases, which would produce an invalid revision range and crash git log (suggesting the use of ^branch exclusion instead); second, ls-remote with patterns does support server-side filtering in Git protocol v2, so replacing it with sequential git fetch calls introduces a performance bottleneck that could be avoided by keeping a pattern-aware LsRemote implementation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread internal/gh/ghui/fetch.go
Comment on lines +242 to +249
revisionRange := []string{"--max-count=10000", tip}
mergeBaseArgs := append([]string{"merge-base", "--octopus", tip}, branches...)
if base, err := vm.repo.Git(ctx, mergeBaseArgs...); err == nil {
if base == tip {
continue
}
revisionRange = []string{"--max-count=10000", base + ".." + tip}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using git merge-base --octopus can return multiple merge bases separated by newlines if there is no single common ancestor. Since vm.repo.Git only trims leading/trailing whitespace, base will contain internal newlines (e.g., "sha1\nsha2"). Constructing base + ".." + tip will result in "sha1\nsha2..tip", which is an invalid revision range and will cause git log to fail with a fatal error.

Instead of using git merge-base to find a single fork point, we can leverage Git's native revision exclusion syntax. Passing ^branch for each branch to git log (e.g., git log tip ^branch1 ^branch2) will automatically exclude all commits reachable from those branches. This is extremely robust, handles multiple branches and complex histories perfectly, and completely eliminates the extra git merge-base process call.

		revisionRange := []string{"--max-count=10000", tip}
		for _, branch := range branches {
			revisionRange = append(revisionRange, "^"+branch)
		}

Comment thread internal/git/git.go Outdated
Comment on lines 312 to 325
// FetchRemoteRef fetches the given fully-qualified ref from the remote and
// returns its commit SHA. This is intentionally not implemented with
// ls-remote: ls-remote patterns cannot filter the server-side ref
// advertisement (only --heads/--tags can), so on remotes with a very large
// number of refs (e.g. GitHub repositories with hundreds of thousands of
// refs/pull/* refs) it downloads the entire advertisement, whereas git fetch
// sends protocol v2 ref-prefix filters so that the server advertises only
// the requested ref.
func (r *Repo) FetchRemoteRef(ctx context.Context, remote string, ref string) (string, error) {
if _, err := r.Git(ctx, "fetch", "--no-tags", remote, ref); err != nil {
return "", err
}
return ret, nil
return r.Git(ctx, "rev-parse", "FETCH_HEAD")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The comment states that ls-remote patterns cannot filter the server-side ref advertisement. However, in Git protocol v2 (which is supported by GitHub and modern Git clients), git ls-remote with specific ref patterns actually uses the ls-refs command with ref-prefix filters. This performs server-side filtering and only advertises the requested refs, without downloading the entire advertisement or any packfiles/objects.

Instead of completely removing LsRemote and replacing it with sequential git fetch calls (which introduce a significant performance bottleneck), we should keep LsRemote but update it to accept optional patterns. This allows us to batch-query multiple refs in a single network round-trip.

// LsRemote lists references in a remote repository matching the given patterns.
// In Git protocol v2, passing specific ref patterns uses server-side ref-prefix
// filtering, making it extremely fast and efficient even on repositories with
// a very large number of refs.
func (r *Repo) LsRemote(ctx context.Context, remote string, refs ...string) (map[string]string, error) {
	args := append([]string{"ls-remote", remote}, refs...)
	out, err := r.Run(ctx, &RunOpts{
		Args:      args,
		ExitError: true,
	})
	if err != nil {
		return nil, errors.Errorf("failed to get remote branches: %v", err)
	}
	ret := make(map[string]string)
	for _, line := range out.Lines() {
		ss := strings.Split(line, "\t")
		if len(ss) != 2 {
			return nil, errors.Errorf("failed to parse the ls-remote output: %q", line)
		}
		ret[ss[1]] = ss[0]
	}
	return ret, nil
}

@tulioz
tulioz force-pushed the sync-perf-large-repos branch from 6a65a72 to 257b022 Compare July 2, 2026 23:01
@tulioz
tulioz marked this pull request as ready for review July 7, 2026 19:08
@tulioz
tulioz requested a review from a team as a code owner July 7, 2026 19:08
@aviator-app

aviator-app Bot commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

✅ FlexReview Status

Common Owner: aviator-co/engineering (expert-load-balance assignment)
Owner and Assignment:

  • ✅ aviator-co/engineering (expert-load-balance assignment)
    Owned Files
    • 🔒 internal/git/git.go
    • 🔒 internal/git/log.go
    • 🔒 internal/gh/ghui/fetch.go
    • 🔒 internal/git/gitui/prune.go

Review SLO: 7 business hours if PR size is <= 200 LOC for the first response.
❕ This PR modifies 206 lines, which is larger than the Review SLO threshold.

@aviator-app
aviator-app Bot requested a review from brain-crystal July 7, 2026 19:08

@jainankit jainankit left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 non-blocking suggestion

Comment thread internal/git/gitui/prune.go Outdated
}
remoteHash, ok := remoteBranches[fmt.Sprintf("refs/pull/%d/head", avbr.PullRequest.Number)]
if !ok {
remoteHash, err := vm.repo.FetchRemoteRef(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this fetch is called in a for-loop, you could batch it.

@aviator-app
aviator-app Bot merged commit d8ac806 into master Jul 8, 2026
4 of 5 checks passed
@aviator-app
aviator-app Bot deleted the sync-perf-large-repos branch July 8, 2026 18:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants