Skip to content

fix(gh): handle stale worktree metadata during prune - #2621

Merged
codeforester merged 1 commit into
mainfrom
bug/2620-20261019-fix-gh-handle-stale-worktree-metadata-during-prune
Oct 19, 2026
Merged

codeforester merged 1 commit into
mainfrom
bug/2620-20261019-fix-gh-handle-stale-worktree-metadata-during-prune

Conversation

@codeforester

Copy link
Copy Markdown
Collaborator

Fixes #2620

Summary

  • Validate branch-attached worktree metadata before dirty checks and removal.
  • Report invalid paths as failures while retaining the path and local branch.
  • Keep detached worktree metadata outside Base branch and PR cleanup, with explicit Git guidance.
  • Add regression coverage and update the command and GitHub workflow documentation.

Validation

  • Focused gh branch/worktree BATS suite: 40 passed.
  • Full source gate: 1,827 Python tests passed and 1,055 shell/BATS tests passed.
  • git diff --check passed.
  • ShellCheck reports one pre-existing informational SC2016 warning at line 583; no new warning was introduced.

Demo Impact: None.

AI context: unchanged; this is an internal cleanup safety and diagnostic fix without product architecture changes.

@codeforester
codeforester requested a review from a team as a code owner October 19, 2026 16:12
@codeforester

Copy link
Copy Markdown
Collaborator Author

Automated review findings

No correctness bugs found - the new base_gh_worktree_is_valid check is verified correctly placed ahead of every git -C "$path" invocation that previously ran unconditionally on a possibly-stale path (checked: base_gh_resolve_physical_path and the SKIP current/default-branch checks earlier in the loop only do cd/pwd -P/string comparisons, no git call). Two design/cleanup findings:

  1. Root cause not fixed, only worked around: base_gh_worktree_is_valid is bolted onto the prune loop as a per-iteration re-validation of paths that base_gh_list_worktree_branches (-> base_git_list_worktree_branches in base-bash-libs) already enumerated. The deeper fix would be to not trust an enumeration source that can return stale/manually-deleted paths in the first place - e.g. driving the loop from git worktree list --porcelain output directly, which git itself keeps authoritative, rather than trusting a separate helper to enumerate branch/path pairs and re-checking git-worktree-ness per path after the fact. Worktree prune is only one call site today; any other consumer of base_git_list_worktree_branches that assumes "enumerated == valid" could hit the same stale-metadata bug independently and would need its own bolted-on guard.

  2. Reimplements an existing validity-check pattern with no shared helper: base_gh_worktree_is_valid's [[ -f "$path/.git" ]] && git -C "$path" rev-parse --is-inside-work-tree is now the 4th ad-hoc copy of "is this path a valid git worktree" in the codebase - base_gh_require_git_repo (gh.sh:582) and two spots in base-bash-libs' lib_git.sh (lines 446, 548) all do their own git rev-parse --is-inside-work-tree check, each slightly differently (one checks -C "$path", another doesn't, this one adds the .git file check). No single source of truth exists for this check, leaving the four call sites free to drift in behavior over time.

Posted via Claude Code

@codeforester

Copy link
Copy Markdown
Collaborator Author

Follow-up finding

A sibling consumer of worktree path resolution may have the same stale-metadata issue this PR fixes for gh worktree prune: base_gh_branch_prune_local (gh_branch_worktree.sh:547) calls base_gh_worktree_path_for_branch -> base_git_worktree_path_for_branch, which is defined in the external base-bash-libs dependency, not in this repo checkout. If that function runs git -C <worktree-path> ... the same way base_gh_worktree_dirty used to (the exact bug this PR fixes for prune), then basectl gh branch prune could still hit a raw git fatal error, or silently mis-skip/mis-delete a branch, when a branch's linked worktree directory has stale/invalid Git metadata.

Couldn't verify this in-repo since the callee lives in base-bash-libs - flagging for someone with access to that repo to check whether the same base_gh_worktree_is_valid-style guard is needed there too.

Posted via Claude Code

@codeforester
codeforester merged commit e6f62d6 into main Oct 19, 2026
25 checks passed
@codeforester
codeforester deleted the bug/2620-20261019-fix-gh-handle-stale-worktree-metadata-during-prune branch October 19, 2026 17:21
@codeforester

Copy link
Copy Markdown
Collaborator Author

Follow-up finding — verified

base_gh_worktree_is_valid (gh_branch_worktree.sh:832-836) does [[ -f "$path/.git" ]] || return 1 before the git rev-parse --is-inside-work-tree check. This only accepts the linked-worktree format where .git is a file pointing back to the main repo's .git/worktrees/<name>. The primary/main checkout's .git is a real directory, not a file - confirmed directly against the current implementation.

In the prune loop (line ~936), the primary worktree is only skipped via the current_worktree/default_branch checks - both depend on runtime state (which worktree the command is invoked from, and which branch the primary checkout happens to be on). If basectl gh worktree prune is run from a different linked worktree while the primary checkout is sitting on some non-default branch (e.g. a teammate left main/ mid-feature-work), neither skip condition matches, and execution reaches base_gh_worktree_is_valid "$path" for the primary worktree's path. Since its .git is a directory, the -f check fails and the function returns invalid - producing a false FAIL ... invalid linked-worktree metadata for a perfectly healthy primary worktree, alarming users/automation despite nothing being wrong.

Whether this is actually reachable depends on whether the worktree-enumeration source (base_gh_list_worktree_branches, implemented in the external base-bash-libs dependency) includes the primary worktree in its output at all - git worktree list normally does list the main worktree as one of its entries, so this is plausible, but I couldn't fully confirm the enumeration behavior without that repo's source in this checkout.

Posted via Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(gh): handle stale worktree metadata during prune

1 participant