From 53a63f2779549434d538b86103c40a0537276bdc Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Mon, 29 Dec 2025 15:51:17 -0800 Subject: [PATCH] fix: edge case in normalizeBeadsRelPath for similar prefixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code review caught that ".beads" would incorrectly match prefixes like ".beads-backup". Changed to match ".beads/" (with trailing slash) to ensure we only match the actual .beads directory. Added test cases for this edge case. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/git/worktree.go | 5 +++-- internal/syncbranch/worktree.go | 5 +++-- internal/syncbranch/worktree_path_test.go | 10 ++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/internal/git/worktree.go b/internal/git/worktree.go index 754ec92d..bd0e011f 100644 --- a/internal/git/worktree.go +++ b/internal/git/worktree.go @@ -321,14 +321,15 @@ func (wm *WorktreeManager) mergeJSONLFiles(srcData, dstData []byte) ([]byte, err } -// normalizeBeadsRelPath strips any leading path components before .beads. +// normalizeBeadsRelPath strips any leading path components before .beads/. // This handles bare repo worktrees where the relative path includes the worktree // name (e.g., "main/.beads/issues.jsonl" -> ".beads/issues.jsonl"). // GH#785: Fix for sync failing across worktrees in bare repo setup. func normalizeBeadsRelPath(relPath string) string { // Use filepath.ToSlash for consistent handling across platforms normalized := filepath.ToSlash(relPath) - if idx := strings.Index(normalized, ".beads"); idx > 0 { + // Look for ".beads/" to ensure we match the directory, not a prefix like ".beads-backup" + if idx := strings.Index(normalized, ".beads/"); idx > 0 { // Strip leading path components before .beads return filepath.FromSlash(normalized[idx:]) } diff --git a/internal/syncbranch/worktree.go b/internal/syncbranch/worktree.go index 7ab233fe..d5956b99 100644 --- a/internal/syncbranch/worktree.go +++ b/internal/syncbranch/worktree.go @@ -1082,14 +1082,15 @@ func formatVanishedIssues(localIssues, mergedIssues map[string]issueSummary, loc return lines } -// normalizeBeadsRelPath strips any leading path components before .beads. +// normalizeBeadsRelPath strips any leading path components before .beads/. // This handles bare repo worktrees where the relative path includes the worktree // name (e.g., "main/.beads/issues.jsonl" -> ".beads/issues.jsonl"). // GH#785: Fix for sync failing across worktrees in bare repo setup. func normalizeBeadsRelPath(relPath string) string { // Use filepath.ToSlash for consistent handling across platforms normalized := filepath.ToSlash(relPath) - if idx := strings.Index(normalized, ".beads"); idx > 0 { + // Look for ".beads/" to ensure we match the directory, not a prefix like ".beads-backup" + if idx := strings.Index(normalized, ".beads/"); idx > 0 { // Strip leading path components before .beads return filepath.FromSlash(normalized[idx:]) } diff --git a/internal/syncbranch/worktree_path_test.go b/internal/syncbranch/worktree_path_test.go index 77d973de..6904d45b 100644 --- a/internal/syncbranch/worktree_path_test.go +++ b/internal/syncbranch/worktree_path_test.go @@ -218,6 +218,16 @@ func TestNormalizeBeadsRelPath(t *testing.T) { input: ".beads/subdir/file.jsonl", expected: ".beads/subdir/file.jsonl", }, + { + name: "similar prefix like .beads-backup not matched", + input: "foo/.beads-backup/.beads/issues.jsonl", + expected: ".beads/issues.jsonl", + }, + { + name: "only .beads-backup no real .beads unchanged", + input: "foo/.beads-backup/file.txt", + expected: "foo/.beads-backup/file.txt", + }, } for _, tt := range tests {