fix: prune pool-maintenance reaps live unborn-branch upstream config - #33
Merged
zheng-weihao merged 1 commit intoAug 13, 2026
Merged
Conversation
…— guard checked-out branches, exempt pool's own checkout
orbit_prune_repo_maintenance judged an orphan branch.<name>.* section by
ref existence alone (rev-parse refs/heads/<name>). An empty repo's
'orbit add' bootstraps an orphan worktree whose scoped branch is UNBORN —
registered in the worktree list, upstream config wired, but no ref — so
any untargeted prune's closing sweep reaped the live worktree's push
routing. First 'git push' after authoring the first commit then failed
128 ('has no upstream branch'), breaking scoped mode's
wired-up-front promise; git's own hint (-u origin ws/<ws>/main) would
publish the internal prefixed name, and the correct repair (hand-editing
branch.*) is one the skill forbids.
Guard: collect branches checked out in worktrees from the same
worktree-list --porcelain pass (unborn branches are listed there, ref or
no ref) and skip their sections — mirroring orbit_prune_raw_residue's
checked-out guard. Two refinements:
- The pool's own checkout does NOT protect: porcelain lists it under an
unborn 'main' for an empty repo, and its clone-written
branch.<default>.* is bookkeeping residue, not push routing — exempting
the pool keeps the previously-correct reap behavior unchanged (the
branch line is attributed to its worktree line via porcelain grouping).
- Normalize $repo with pwd -P before any path comparison: porcelain
prints physical paths (macOS /var -> /private/var), so a logical $repo
never matched the pool's own worktree line — the pre-existing
registration-side pool exemption was latently dead, saved only by the
-e fallback. The logical basename is kept for the summary line so a
symlinked pool dir's line stays consistent with its group header.
spec-warnings.md: the orphan-config row now defines the boundary —
'gone' = no ref AND checked out in no non-pool worktree; the pool's own
checkout never counts.
tests/09_prune.bats: empty-repo regression pair — (1) bare prune after
'orbit add' keeps the worktree's branch.ws/dev/main.* while still
reaping the pool's branch.main.*; (2) done -> prune closes the
lifecycle: D1 removes the worktree, the guard self-limits, both sections
reaped.
Signed-off-by: zheng-weihao <zheng-weihao@outlook.com>
This was referenced Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
orbit_prune_repo_maintenancejudged an orphanbranch.<name>.*section by ref existence alone (rev-parse refs/heads/<name>). An empty repo'sorbit addbootstraps an orphan worktree whose scoped branch is unborn — registered in the worktree list, upstream config wired, but no ref — so any untargetedorbit prune's closing sweep reaped the live worktree's push routing. The firstgit pushafter authoring the first commit then fails 128 (has no upstream branch), breaking scoped mode's wired-up-front promise. Recovery paths are all poor: git's own hint (git push -u origin ws/<ws>/main) publishes the internal prefixed branch name, and the correct repair (hand-editingbranch.*) is one the skill's safety rules forbid.Repro:
orbit clone <empty-repo>→orbit add→ bareorbit prune→ commit →git push→ 128.Fix
Collect branches checked out in worktrees from the same
worktree list --porcelainpass (unborn branches are listed there, ref or no ref) and skip their config sections — mirroringorbit_prune_raw_residue's checked-out guard. Two refinements:main; its clone-writtenbranch.<default>.*is bookkeeping residue, not push routing. Exempting the pool (via porcelain worktree→branch line grouping) keeps the previously-correct reap behavior unchanged.pwd -Pnormalization before path comparison. Porcelain prints physical paths (macOS/var→/private/var); a logical$reponever matched the pool's own worktree line, so the pre-existing registration-side pool exemption was latently dead (saved only by the-efallback). The logical basename is kept for the summary line so a symlinked pool dir stays consistent with its group header.docs/spec-warnings.md: the orphan-config row now defines the boundary — gone = no ref AND checked out in no non-pool worktree; the pool's own checkout never counts.Tests
tests/09_prune.batsempty-repo regression pair:orbit addkeepsbranch.ws/dev/main.*while still reaping the pool'sbranch.main.*done→prunecloses the lifecycle: D1 removes the worktree, the guard self-limits, both sections reapedFull suite: 366/366 passing.