The error message 'path exists but is not a valid git worktree' was appearing
in daemon.log when the daemon attempted to use an existing worktree that was
in the git worktree list but had other issues (broken sparse checkout, etc.).
Root cause:
- CreateBeadsWorktree only checked isValidWorktree (is it in git worktree list)
- CheckWorktreeHealth was called separately and checked additional things
- If the worktree passed isValidWorktree but failed health check, an error
was logged and repair was attempted
Fix:
- CreateBeadsWorktree now performs a full health check when it finds an
existing worktree that's in the git worktree list
- If the health check fails, it automatically removes and recreates the
worktree
- Removed redundant CheckWorktreeHealth calls in daemon_sync_branch.go and
syncbranch/worktree.go since CreateBeadsWorktree now handles this internally
This eliminates the confusing error message and ensures worktrees are always
in a healthy state after CreateBeadsWorktree returns successfully.
Problem:
When the daemon auto-sync runs with --auto-commit --auto-push, the sync
branch pull operation consistently fails with:
fatal: '.git/beads-worktrees/beads-metadata' is a missing but already
registered worktree; use 'add -f' to override, or 'prune' or 'remove'
to clear
This occurs because:
1. Daemon creates worktree at .git/beads-worktrees/<branch>
2. Git registers it in .git/worktrees/<branch>
3. After the operation, worktree contents are removed
4. Git registration persists, pointing to the now-empty path
5. Subsequent CreateBeadsWorktree calls fail because os.Stat() returns
error (path missing), so no cleanup happens, then git worktree add
fails because git still has it registered
Root cause:
The git worktree add commands in CreateBeadsWorktree() did not use the
-f (force) flag, which is needed to override the "missing but already
registered" state.
Solution:
Add -f flag to both git worktree add commands (for existing branch and
new branch cases). Per git documentation, -f overrides the safeguard
that prevents creating a worktree when the path is already registered
but missing.
The existing git worktree prune call (line 30-32) was intended to handle
this, but it runs before the path check and may not always clear the
registration in time. The -f flag provides a robust fallback.
Testing:
- All existing worktree tests pass
- Added regression test TestCreateBeadsWorktree_MissingButRegistered
that simulates the exact issue #609 scenario
Fixes#609
Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
Fix daemon auto-sync delete mutation not reflected in sync branch
When deleting an issue with `bd delete <id> --force`, the daemon auto-sync now properly removes the deleted issue from the sync branch.
**Problem:** The merge logic saw fewer local issues (due to deletion) and would re-add the deleted issue.
**Solution:** Add `ForceOverwrite` option to bypass merge logic when mutations occur. Mutation-triggered exports are authoritative and should overwrite, not merge.
Reviewed-by: stevey
When syncing JSONL to worktree, if the worktree has more issues than
local, merge them instead of blindly overwriting. This prevents fresh
clones from accidentally deleting remote issues when they sync with
fewer issues than the sync branch.
Root cause of GitHub #464: A fresh clone with sync-branch configured
would start with an empty database (since JSONL is on sync-branch, not
HEAD). When syncing, the local 1-issue JSONL would overwrite the
remotes 10-issue JSONL, and the subsequent 3-way merge would see this
as local deleted 9 issues causing deletion to win.
The fix compares issue counts and triggers a merge when local has fewer
issues than the worktree (remote). Uses 3-way merge with empty base to
combine both sets of issues.
Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Add #nosec directives with explanations for all gosec warnings in worktree operations
- Tighten directory permissions from 0755 to 0750 for better security
- Fix misspellings: archaeological -> archeological, cancelled -> canceled
- Remove unused jsonlPath parameter from syncBranchCommitAndPush
- Change branchExists to return bool instead of (bool, error) - error was never used
All changes maintain backward compatibility and improve code quality.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>