Skip to content

Similar-repo comparison stays on "Comparing repositories..." forever when siblings share a submodule path (or any unreadable tracked entry) #436

Description

@matt-edmondson

What's wrong

DiffRepos (ProjectDirector/ProjectDirector.cs, ~lines 1388–1393) intersects the git ls-files output of two sibling repos and reads every shared path with ReadFileOrEmpty (~lines 1407–1421). That helper only catches FileNotFoundException and DirectoryNotFoundException.

git ls-files lists a submodule's gitlink, for example external, as a tracked entry. On disk that path is always a directory, even when the submodule was never initialised. So when two siblings share a submodule path, File.ReadAllText("<repo>/external") throws UnauthorizedAccessException, which isn't caught.

The exception faults the background task started by CompareSiblingsAsync. Nothing observes that task, so TryApplySimilarRepoDiffs never runs, SimilarReposPending stays true, and no log line says what happened.

Other failures take the same path:

  • a tracked symlink to a directory
  • a file locked by another process on Windows (IOException)
  • a permission error

DiffSingleFile (~line 1452) reads the same way and has the same gap. It runs on the render thread, though, so there the exception would take down the render loop instead of hanging a panel.

Failure scenario

Two sibling repos each contain a 160000 gitlink at external. Selecting either one leaves the Similar Repos, Compare Repo and Compare File panels showing "Comparing repositories..." indefinitely. This was reproduced with a scratch test. It awaited CompareSiblingsAsync, got UnauthorizedAccessException: Access to the path '.../external' is denied, and afterwards SimilarReposPending was still True.

Suggested fix

  • In DiffRepos, skip matches that are directories, or filter gitlinks out using git ls-files -s mode 160000.
  • In ReadFileOrEmpty, also catch UnauthorizedAccessException and IOException, and treat them as empty or skip the file.
  • Wrap the body of the comparison task so any failure still clears the pending state and logs the reason, instead of faulting silently.

Acceptance criteria

  • Two siblings that share a submodule path compare successfully, with the gitlink ignored.
  • An unreadable tracked file never leaves a repo stuck in the pending state, and the reason shows up in the log.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions