diff --git a/src/ClaudeDo.Ui/Services/RepoScanner.cs b/src/ClaudeDo.Ui/Services/RepoScanner.cs index 22418166..ab25250a 100644 --- a/src/ClaudeDo.Ui/Services/RepoScanner.cs +++ b/src/ClaudeDo.Ui/Services/RepoScanner.cs @@ -67,9 +67,7 @@ public static class RepoScanner } } - private static bool IsRepo(string dir) - { - var gitPath = Path.Combine(dir, ".git"); - return Directory.Exists(gitPath) || File.Exists(gitPath); - } + // A real clone has .git as a directory. Worktrees and submodules have it as a file + // ("gitdir: ...") — those are not standalone repos and would flood the list. + private static bool IsRepo(string dir) => Directory.Exists(Path.Combine(dir, ".git")); } diff --git a/tests/ClaudeDo.Ui.Tests/RepoScannerTests.cs b/tests/ClaudeDo.Ui.Tests/RepoScannerTests.cs index d52178d5..a7aaaaff 100644 --- a/tests/ClaudeDo.Ui.Tests/RepoScannerTests.cs +++ b/tests/ClaudeDo.Ui.Tests/RepoScannerTests.cs @@ -35,15 +35,17 @@ public sealed class RepoScannerTests : IDisposable } [Fact] - public void Scan_TreatsDotGitFileAsRepo() + public void Scan_IgnoresWorktrees() { - var repo = MakeDir("worktree-repo"); - File.WriteAllText(Path.Combine(repo, ".git"), "gitdir: ../somewhere"); + var repo = MakeDir("repo-a"); + Directory.CreateDirectory(Path.Combine(repo, ".git")); + var worktree = MakeDir("repo-a-my-task"); + File.WriteAllText(Path.Combine(worktree, ".git"), "gitdir: ../repo-a/.git/worktrees/my-task"); var result = RepoScanner.Scan(_root); Assert.Single(result); - Assert.Equal("worktree-repo", result[0].Name); + Assert.Equal("repo-a", result[0].Name); } [Fact]