Repository navigation
fix: orbit switch always fetches before checking out a remote branch - #22
Merged
Merged
Conversation
orbit_ensure_remote_branch skipped the fetch whenever origin/<branch> existed locally, so switching to a branch whose remote history advanced or was force-pushed after the last fetch silently checked out the abandoned commit — and git status looked normal because the upstream IS the stale ref. Drop the exists-guard: fetch unconditionally, and when the fetch fails (offline) fall back to the local ref with a possibly-stale warning; fail only when there is no local ref at all. orbit add default mode goes through the same path, so worktrees are now always based on the fresh default branch too. Regression test: switch to a remote branch, rewrite it via force-push, switch again from a second workspace — asserts the new head is checked out (verified red without the fix, green with it). Signed-off-by: zheng-weihao <zheng-weihao@outlook.com>
zheng-weihao
force-pushed
the
fix-switch-stale-ref
branch
from
July 28, 2026 05:21
011b28a to
0edb836
Compare
zheng-weihao
added a commit
that referenced
this pull request
Jul 28, 2026
…mode docs Review follow-ups for #16-#22: - reconcile: never touch foreign fetch refspecs. The exact-refspec match also captured a user-configured wildcard (+refs/heads/*:...) converting the pool to full fetch, parsed its branch as '*', found no such remote branch, and silently removed it. Git refnames forbid '*', so any glob entry is foreign config — now skipped in both phases. - switch: roll back the just-registered fetch refspec when the remote branch turns out not to exist. The leftover violated the invariant "every exact refspec points at a real remote branch" and broke every bare fetch in the pool until the next reconcile touchpoint. - remove_fetch_refspec: prefer atomic `git config --unset --fixed-value` (git >= 2.26) over unset-all + re-add rebuild, which loses every fetch refspec if interrupted mid-rebuild. Older git keeps the rebuild path (floor is git 2.20). - brief extract: recover from an unclosed HTML block after a 50-line budget instead of letting it swallow the rest of the README; typed fences — a ~~~ line inside a ``` fence is content, not a toggle. - status: print the raw-mode conversion steering on stderr, closing the gap with context/done per the spec-warnings steering registry. - docs: scoped is the default branch mode everywhere — SKILL.md, CONSTRAINTS.md (both sections), USAGE.md, spec-commands, recipes, and comparison still said "default = raw" / "scoped opt-in", contradicting the workflow section since #18. Tests: 220/220 (wildcard preservation, failed-switch rollback, unclosed HTML recovery, typed fences, status steering). Lint clean. Signed-off-by: zheng-weihao <zheng-weihao@outlook.com>
zheng-weihao
added a commit
that referenced
this pull request
Jul 28, 2026
…mode docs (#23) Review follow-ups for #16-#22: - reconcile: never touch foreign fetch refspecs. The exact-refspec match also captured a user-configured wildcard (+refs/heads/*:...) converting the pool to full fetch, parsed its branch as '*', found no such remote branch, and silently removed it. Git refnames forbid '*', so any glob entry is foreign config — now skipped in both phases. - switch: roll back the just-registered fetch refspec when the remote branch turns out not to exist. The leftover violated the invariant "every exact refspec points at a real remote branch" and broke every bare fetch in the pool until the next reconcile touchpoint. - remove_fetch_refspec: prefer atomic `git config --unset --fixed-value` (git >= 2.26) over unset-all + re-add rebuild, which loses every fetch refspec if interrupted mid-rebuild. Older git keeps the rebuild path (floor is git 2.20). - brief extract: recover from an unclosed HTML block after a 50-line budget instead of letting it swallow the rest of the README; typed fences — a ~~~ line inside a ``` fence is content, not a toggle. - status: print the raw-mode conversion steering on stderr, closing the gap with context/done per the spec-warnings steering registry. - docs: scoped is the default branch mode everywhere — SKILL.md, CONSTRAINTS.md (both sections), USAGE.md, spec-commands, recipes, and comparison still said "default = raw" / "scoped opt-in", contradicting the workflow section since #18. Tests: 220/220 (wildcard preservation, failed-switch rollback, unclosed HTML recovery, typed fences, status steering). Lint clean. Signed-off-by: zheng-weihao <zheng-weihao@outlook.com>
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_ensure_remote_branchskipped the fetch wheneverorigin/<branch>existed locally. Switching to a branch whose remote history advanced or was force-pushed after the last fetch silently checked out the abandoned commit — andgit statuslooked completely normal, because the upstream is the stale ref, so the staleness is invisible. Continue working there and your new commits stack on abandoned history (rebase/force-push workflows hit this constantly). Hit for real during the #20 work: after a rebase + force-push, switching back to the PR branch checked out the pre-rebase commit.Fix
Drop the exists-guard in
orbit_ensure_remote_branch: always fetch. When the fetch fails (offline), fall back to the local ref with apossibly-stalewarning; fail only when there is no local ref at all.Both call sites benefit:
orbit switch <branch>— checks out the current remote headorbit add(default mode) — new worktrees are based on the fresh default branch, not a weeks-old refTests
New regression test in
06_worktree_integration: switch to a remote branch → rewrite it via force-push → switch again from a second workspace (stale ref present in pool) → asserts the new head is checked out and the pool ref is refreshed. Verified red without the fix, green with it.Full suite: 216/216 ok,
make lintclean.