Skip to content

Report only a working-tree root as cloned, not a directory inside another repository [patch] - #204

Open
matt-edmondson wants to merge 1 commit into
mainfrom
fix/185-is-cloned-root
Open

matt-edmondson wants to merge 1 commit into
mainfrom
fix/185-is-cloned-root

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #185

Summary

GitRepository.IsClonedAsync() asked git rev-parse --is-inside-work-tree. That check walks up the directory tree, so it returned true for an empty directory beneath another repository's working tree. As a result, "clone if not cloned" skipped the clone, and Status(), Commit() and the other verbs then ran silently against the outer repository.

  • New GitProbes.IsWorkTreeRootAsync runs rev-parse --is-inside-work-tree --show-cdup. A path counts as cloned only when it is inside a working tree and --show-cdup is empty, meaning the path is the root.
  • --show-cdup looks at the working tree, not the git directory. Submodules, linked worktrees and --separate-git-dir checkouts, whose .git is a file, therefore still count as roots, which covers the cases Init() reports AlreadyExisted = false when re-initializing a submodule, worktree or --separate-git-dir repository, hiding an ignored --initial-branch #138 had to handle. A bare repository has no working tree and still counts as not cloned, as before.
  • IGitClient.IsRepositoryAsync / OpenAsync keep the "inside a working tree" semantics through the unchanged GitProbes.IsWorkTreeAsync.

Tests

  • Integration:
    • An empty directory and a non-empty subdirectory inside a repository report false, and the outer repository reports true.
    • A --separate-git-dir checkout and a linked worktree report true.
    • A submodule checkout reports true, and the superproject directory holding it reports false.
  • Unit: scripted true\n../ output reports false.
  • With the fix reverted, the nested-directory and submodule-parent integration tests fail. With it applied, the full suite passes (790 tests, git 2.43).

🤖 Generated with Claude Code

https://claude.ai/code/session_019BwRbgKQMY5pZraxHBjxqM


Generated by Claude Code

…ther repository [patch]

IsClonedAsync asked `rev-parse --is-inside-work-tree`, which walks up
the directory tree, so an empty directory beneath another repository's
working tree reported as cloned. "Clone if not cloned" then skipped the
clone and later verbs ran against the outer repository.

It now asks `--is-inside-work-tree --show-cdup` and requires an empty
way up, so only the root counts. Submodules, linked worktrees and
--separate-git-dir checkouts are still roots; IGitClient.IsRepositoryAsync
keeps its "inside a working tree" contract.

Fixes #185

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019BwRbgKQMY5pZraxHBjxqM
@sonarqubecloud

sonarqubecloud Bot commented Oct 9, 2026

Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor Author

Cross-Platform Tests / Test on macos-latest was cancelled at the job's 15-minute timeout. It stalled inside the Test step after a normal build. I don't think this PR caused it:

  • The same job stalled the same way on Redact tokens, passwords and device codes from credential ToString [patch] #202 (run 37870035724, attempt 1, a credential ToString change that doesn't touch git probing). Attempt 2 passed in about 30 seconds.
  • On this PR's head, the macOS test leg of the shared pipeline (ci / .NET / Test on macos-latest) passed and ran the same suite. So did the Linux leg of this workflow.

No fix exists yet for the intermittent macOS stall, so I'm re-running the failed job once. If it stalls again, I'll treat it as real and investigate it on this PR.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

The re-run of Cross-Platform Tests / Test on macos-latest also hit the 15-minute timeout inside Test. That's two stalls in a row on this PR, so I'm no longer treating it as a flake. It still doesn't look like this PR's code is hanging:

  • On the same commit and the same macOS image (git 2.55.0, arm64), the shared pipeline's ci / .NET / Test on macos-latest ran the full suite in 31s: 790 passed, 0 skipped. That includes every new IsCloned* integration test (submodule, worktree, separate-git-dir, nested directory).
  • The workflow that stalls runs the same test DLL. The visible differences are the plain dotnet test --no-build --configuration Release invocation and KTSU_GIT_INTEGRATION_TESTS_REQUIRED=1. It also stalled on Redact tokens, passwords and device codes from credential ToString [patch] #202 earlier today, which doesn't touch git probing.
  • GitHub returns 404 for the cancelled jobs' logs, so I can't see which test it was running when it stalled.

I don't have a fix to push from here, and I've used my one re-run. Proposed next step (not pushed, since it widens this PR into CI config): add a hang dump to that workflow's Test step so the next stall names the test:

run: dotnet test --no-build --configuration Release -- --hangdump --hangdump-timeout 5m

(Microsoft Testing Platform's hang-dump extension may need Microsoft.Testing.Extensions.HangDump referenced by the test project.) Once the stalling test is known, the fix is easy to target. Leaving this for a maintainer to decide.


Generated by Claude Code

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

Labels

None yet

Projects

None yet

2 participants