fix(cli): resolve repo by filesystem identity when stored path spelling differs#282
Open
jimboswankster wants to merge 2 commits into
Open
Conversation
…ng differs The repo lookup compared the stored working path to the cwd's git root by exact string match. The same directory frequently spells differently: git rev-parse --git-common-dir preserves whatever casing a worktree was created with (case-insensitive filesystems on macOS/Windows), and paths can reach the repo through symlink aliases. Any spelling mismatch surfaced as 'repo not initialized' even though the repo was registered. Fall back to filesystem identity (os.SameFile) over the registered repos when exact lookup misses, for both the cwd git root and the main worktree root.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
findRepoto collect candidate roots (git root plus the main worktree root), attempt exact path lookups against each, then fall back to a newrepoByPathIdentityhelper that matches a registered repo viaos.SameFileinstead of erroring withrepo not initialized.db.ListReposto enumerate registered repos for the identity fallback, and documented the command-time resolution behavior in the gate-model concepts doc.Risk Assessment
✅ Low: A small, well-bounded fix that only adds a filesystem-identity fallback on the already-failing lookup path, using os.SameFile semantics that cannot false-match unrelated directories, with targeted tests covering both the symlink and case-variant cases.
Testing
Reviewed the diff and confirmed HEAD is the target commit, then drove the actual end-user surface: I built the base and target binaries and exercised the documented bug through the real
no-mistakes runscommand against the real product SQLite DB, seeding a registered repo whose stored path spelled the same directory differently (symlink alias and case variant). The captured CLI transcripts show the exact before→after flip — base errors with "repo not initialized" (exit 1), target resolves the repo and prints "no runs yet…" (exit 0). I also ran the new unit test (both subtests pass, including the case-variant path that confirms this filesystem is case-insensitive), the affected packages under the race detector, and the fullgo test -race ./...suite — all green. Transient build binaries were removed and the working tree is clean.Evidence: CLI before/after — symlink-alias stored path (no-mistakes runs)
stored repo working_path : .../work-alias (symlink -> same dir) === BEFORE FIX (4893e32) === $ cd <repo> && no-mistakes runs repo not initialized (run 'no-mistakes init' first) [exit 1] === AFTER FIX (9990d1a) === $ cd <repo> && no-mistakes runs no runs yet. Push through the gate to start a pipeline: git push no-mistakes <branch> [exit 0]Evidence: CLI before/after — case-variant stored path (no-mistakes runs)
stored repo working_path : .../WORK (case variant of same dir) === BEFORE FIX (4893e32) === $ cd <repo> && no-mistakes runs repo not initialized (run 'no-mistakes init' first) [exit 1] === AFTER FIX (9990d1a) === $ cd <repo> && no-mistakes runs no runs yet. Push through the gate to start a pipeline: git push no-mistakes <branch> [exit 0]Pipeline
Updates from git push no-mistakes
⏭️ **intent** - skipped
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
internal/cli/root.go:160- In repoByPathIdentity the loop iteratesfor each repo { for each candidate }, so a repo aliasing mainRoot can be returned before one aliasing gitRoot, losing the gitRoot-first preference the exact-match loop enforces. This only matters if two distinct repo records both have string-mismatched (case/symlink) paths resolving to gitRoot and mainRoot simultaneously — effectively impossible given init normalizes to the resolved main root and reattachRelocatedRepo prevents duplicates. Also note ListRepos has no ORDER BY, so iteration order is unspecified. No action needed; documenting the subtlety.✅ **Test** - passed
✅ No issues found.
Built before/after binaries:go build -o ./bin/nm-target ./cmd/no-mistakes(HEAD 9990d1a) and the same against reverted base source (4893e32) → ./bin/nm-baseManual product transcript (symlink alias): seeded areposrow viasqlite3with working_path = symlink alias of the git root, then ranno-mistakes runsfrom inside the repo with both binaries — base printed 'repo not initialized' (exit 1), target resolved and printed 'no runs yet…' (exit 0)Manual product transcript (case variant): same flow with working_path = case variant (.../WORK vs .../work) — base failed, target resolvedgo test ./internal/cli -run '^TestFindRepoResolvesAliasedWorkingPath$' -v -count=1(symlink_alias and case_variant subtests both PASS; case_variant not skipped, so os.SameFile path exercised)go test -race ./internal/cli ./internal/db -count=1go test -race ./...(full suite, all packages ok)✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.