feat(checkout): accept @{N} reflog refs for detached-HEAD recovery (muse#46)
Verified muse#46's full scope (pull/shelf reflog coverage, reflog expire/delete/exists subcommands, gc integration, @{N} resolution in rev-parse/reset/read/diff) was already implemented and covered by 491 passing tests (RL_01-RL_30) across tests/test_cmd_reflog_coverage.py, tests/test_cmd_reflog_expire.py, tests/test_cmd_reflog_delete.py, tests/test_cmd_gc_reflog.py, tests/test_reflog_ref_resolution.py, and tests/test_cmd_reflog_exists.py.
One real gap found during live verification: `muse checkout @{N}` was listed in the ticket's "Commands that must accept @{N}" table but actually raised "Invalid branch name" -- checkout.py's early commit-ref detection (_is_commit_ref) recognized sha256:/hex/~N forms but not @{N}/branch@{N}, so "@{1}" fell through to validate_branch_name, which rejects "{"/"}" as forbidden characters, before ever reaching resolve_commit_ref (the only code path that understands reflog refs).
Fixed by adding muse/core/reflog.py::is_reflog_ref_spec() -- a cheap syntactic @{...} check reusing the existing _AT_N_RE pattern -- and wiring it into checkout.py's _is_commit_ref detection. 4 new tests in tests/test_reflog_ref_resolution.py::TestCheckoutAtN confirm detached-HEAD checkout via @{N} and branch@{N}, out-of-range rejection, and that the "Invalid branch name" regression never recurs. Confirmed via genuine RED (reverted the checkout.py wiring, 3/4 new tests failed) -> GREEN.
Live-verified the ticket's own end-to-end recovery scenario via muse-dev: commit A -> commit B -> muse reset --hard HEAD~1 -> muse reset @{1} -> back at commit B.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Semantic Changes
9 symbols
Files Changed
~3
1249 in snapshot
0 comments
muse hub commit comment sha256:c6483b12ab17f2b6b1de0abb0b7f40fe0c53456c1e503f00136d903ed8d48e0e --body "your comment"
No comments yet. Be the first to start the discussion.