{"record":{"id":"4dd21fae62fd0bce","repo":"gastownhall/beads","slug":"target-common-git-directory-changed","errorCode":null,"errorMessage":"target common git directory changed","messagePattern":"target common git directory changed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/worktree_cmd.go","lineNumber":1418,"sourceCode":"\t\t}\n\t\treturn worktreeRevalidationObservation{facts: facts, err: fmt.Errorf(\"registered target identity changed\")}\n\t}\n\tfacts.Registration = worktreeremove.InvariantStable\n\tfacts.LockPrune = worktreeremove.InvariantStable\n\tfacts.TargetPath = worktreeremove.InvariantStable\n\n\tcurrentTarget, err := inspectWorktreeTarget(ctx, plan.git, currentEntry)\n\tif err != nil {\n\t\treturn worktreeRevalidationObservation{facts: facts, err: err}\n\t}\n\tif !sameWorktreePath(currentTarget.gitDir, plan.target.gitDir) {\n\t\tfacts.GitAdminDirectory = worktreeremove.InvariantChanged\n\t\treturn worktreeRevalidationObservation{facts: facts, err: fmt.Errorf(\"target git directory changed\")}\n\t}\n\tfacts.GitAdminDirectory = worktreeremove.InvariantStable\n\tif !sameWorktreePath(currentTarget.commonDir, plan.commonDir) {\n\t\tfacts.CommonDirectory = worktreeremove.InvariantChanged\n\t\treturn worktreeRevalidationObservation{facts: facts, err: fmt.Errorf(\"target common git directory changed\")}\n\t}\n\tfacts.CommonDirectory = worktreeremove.InvariantStable\n\tif currentTarget.headOID != plan.target.headOID {\n\t\tfacts.Head = worktreeremove.InvariantChanged\n\t\treturn worktreeRevalidationObservation{facts: facts, err: fmt.Errorf(\"target HEAD changed from %s to %s\", plan.target.headOID, currentTarget.headOID)}\n\t}\n\tfacts.Head = worktreeremove.InvariantStable\n\tif currentTarget.status != plan.target.status {\n\t\tif (currentTarget.status == \"\") != (plan.target.status == \"\") {\n\t\t\tfacts.Cleanliness = worktreeremove.InvariantChanged\n\t\t} else {\n\t\t\tfacts.Cleanliness = worktreeremove.InvariantStable\n\t\t}\n\t\tfacts.StatusBytes = worktreeremove.InvariantChanged\n\t\treturn worktreeRevalidationObservation{facts: facts, err: fmt.Errorf(\"target cleanliness changed\")}\n\t}\n\tfacts.Cleanliness = worktreeremove.InvariantStable\n\tfacts.StatusBytes = worktreeremove.InvariantStable","sourceCodeStart":1400,"sourceCodeEnd":1436,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/worktree_cmd.go#L1400-L1436","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: repo moved after plan was built\n$ bd worktree remove feature\n// error: target common git directory changed\n// after\n$ cd /new/location/repo && git worktree repair\n$ bd worktree remove feature   # fresh plan","handlingStrategy":"retry","validationCode":"cur=$(git -C /wt/feature rev-parse --path-format=absolute --git-common-dir)\n[ \"$cur\" = \"$RECORDED_COMMON_DIR\" ] || { echo 'repo common dir moved; rebuild plan'; exit 1; }","typeGuard":"func commonDirStable(before, after string) bool {\n\treturn filepath.Clean(before) == filepath.Clean(after)\n}","tryCatchPattern":"obs := revalidateWorktreePlan(ctx, plan)\nif obs.err != nil && strings.Contains(obs.err.Error(), \"common git directory changed\") {\n\treturn fmt.Errorf(\"repository structure changed; re-run bd worktree remove from the primary repo\")\n}","preventionTips":["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"],"tags":["git","worktree","race-condition","repository-mismatch"],"backgroundTag":"stale-worktree-state","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}