Skip to content

Workspace repo discovery follows directory symlinks: a symlink loop lists the same repo dozens of times, and repo fetch then runs that many concurrent fetches into it #232

Open

Description

@matt-edmondson

What's wrong

DiscoverGitReposRecursive (KtsuTools.Repo/RepoService.cs:1144-1168) recurses into every entry Directory.GetDirectories returns. That includes directory symlinks and junctions (reparse points). It never skips them and never de-duplicates by real path, so:

  • A symlink that points at a repo, or at a directory above one, lists that repo again under a second path.
  • A symlink that points back up the tree (tools/loop -> ..) is followed repeatedly until the OS symlink-depth limit throws. Every level on the way adds the same repos again.

The callers include TryDiscoverWorkspaceRepos (line ~700, used by ktools git and repo lfs install), PullAllAsync (~507), FetchAllAsync and WalkAndCacheAsync. SaveCacheAsync de-duplicates by path string only, so every alias reaches the cache as a separate repo.

Reproduction

Take a workspace with ws/A/.git and ws/tools/loop -> ... A copy of the function returns 41 entries, every one of them repo A, reached as ws/tools/loop/A, ws/tools/loop/tools/loop/A, and so on.

With that workspace:

  • ktools git status prints A 41 times.
  • repo pull runs git pull --autostash in A 41 times.
  • repo fetch is parallel by default, so it runs 41 concurrent fetches into the same repository. They contend for ref locks, and the ones that lose report failures.

Suggested fix

Acceptance criteria

  • A test with a symlinked subdirectory that loops back to the workspace root returns each repo exactly once and does not throw.
  • A test with a symlink pointing directly at a repo returns that repo once.

Related but distinct: #230 (the AllDirectories scans stopping on an unreadable directory) and #188 (a symlinked workspace root in sync).

Activity

  1. matt-edmondson commented on Sep 30, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions