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.
What's wrong
DiffRepos(ProjectDirector/ProjectDirector.cs, ~lines 1388–1393) intersects thegit ls-filesoutput of two sibling repos and reads every shared path withReadFileOrEmpty(~lines 1407–1421). That helper only catchesFileNotFoundExceptionandDirectoryNotFoundException.git ls-fileslists a submodule's gitlink, for exampleexternal, 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")throwsUnauthorizedAccessException, which isn't caught.The exception faults the background task started by
CompareSiblingsAsync. Nothing observes that task, soTryApplySimilarRepoDiffsnever runs,SimilarReposPendingstaystrue, and no log line says what happened.Other failures take the same path:
IOException)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
160000gitlink atexternal. 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 awaitedCompareSiblingsAsync, gotUnauthorizedAccessException: Access to the path '.../external' is denied, and afterwardsSimilarReposPendingwas stillTrue.Suggested fix
DiffRepos, skip matches that are directories, or filter gitlinks out usinggit ls-files -smode160000.ReadFileOrEmpty, also catchUnauthorizedAccessExceptionandIOException, and treat them as empty or skip the file.Acceptance criteria