gastownhall/beads · error
target common git directory changed
Error message
target common git directory changed
What it means
Revalidation also compares the target's common git directory with the plan's recorded commonDir. A mismatch means the worktree now shares metadata with a different repository (or the repo's common dir moved), so executing the prepared plan could damage the wrong repository. bd aborts, marking CommonDirectory as Changed, and reports this error.
Solutions
- Rebuild by re-running `bd worktree remove` so the plan captures the current common dir
- Verify the main repo path hasn't moved; update the worktree with `git worktree repair` from the primary repo if it has
- Serialize operations: don't move/re-clone the repository while a worktree removal is pending
Example fix
// before: repo moved after plan was built $ bd worktree remove feature // error: target common git directory changed // after $ cd /new/location/repo && git worktree repair $ bd worktree remove feature # fresh plan
Defensive patterns
Strategy: retry
Validate before calling
cur=$(git -C /wt/feature rev-parse --path-format=absolute --git-common-dir)
[ "$cur" = "$RECORDED_COMMON_DIR" ] || { echo 'repo common dir moved; rebuild plan'; exit 1; } Type guard
func commonDirStable(before, after string) bool {
return filepath.Clean(before) == filepath.Clean(after)
} Try / catch
obs := revalidateWorktreePlan(ctx, plan)
if obs.err != nil && strings.Contains(obs.err.Error(), "common git directory changed") {
return fmt.Errorf("repository structure changed; re-run bd worktree remove from the primary repo")
} Prevention
- Don't move or re-clone the primary repo while worktree operations are pending
- Run `git worktree repair` from the primary repo after any repo relocation
- Keep the primary repo at a stable absolute path (avoid renameable mount points)
- Always execute removal promptly after planning; never persist plans across repo restructures
When it happens
Trigger: Executing a removal plan after the repository's common dir changed (repo moved/cloned, .git structure rearranged, worktree re-linked to another clone) between plan build and execution.
Common situations: The main repo was moved or its path changed (macOS /Volumes mounts, renamed directories) after the plan was built; the worktree was re-added against a different clone; `git worktree repair` relinked to a different primary.
Related errors
- .gitignore changed before removal
- registered target identity changed
- registered target identity changed (git marker mismatch)
- target cleanliness changed
- target common git directory
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4dd21fae62fd0bce.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/bd/worktree_cmd.go:1418
}
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("registered target identity changed")}
}
facts.Registration = worktreeremove.InvariantStable
facts.LockPrune = worktreeremove.InvariantStable
facts.TargetPath = worktreeremove.InvariantStable
currentTarget, err := inspectWorktreeTarget(ctx, plan.git, currentEntry)
if err != nil {
return worktreeRevalidationObservation{facts: facts, err: err}
}
if !sameWorktreePath(currentTarget.gitDir, plan.target.gitDir) {
facts.GitAdminDirectory = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("target git directory changed")}
}
facts.GitAdminDirectory = worktreeremove.InvariantStable
if !sameWorktreePath(currentTarget.commonDir, plan.commonDir) {
facts.CommonDirectory = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("target common git directory changed")}
}
facts.CommonDirectory = worktreeremove.InvariantStable
if currentTarget.headOID != plan.target.headOID {
facts.Head = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("target HEAD changed from %s to %s", plan.target.headOID, currentTarget.headOID)}
}
facts.Head = worktreeremove.InvariantStable
if currentTarget.status != plan.target.status {
if (currentTarget.status == "") != (plan.target.status == "") {
facts.Cleanliness = worktreeremove.InvariantChanged
} else {
facts.Cleanliness = worktreeremove.InvariantStable
}
facts.StatusBytes = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("target cleanliness changed")}
}
facts.Cleanliness = worktreeremove.InvariantStable
facts.StatusBytes = worktreeremove.InvariantStableView on GitHub (pinned to 71377f2769)