feat: version tag relative resolution (tilde notation) + non-SemVer decision (muse#57 items 5-6)
Item 6 (decided, no code change): keep muse tag's strict SemVer 2.0 boundary; freeform version workflows (nightly-20260628, 2026.06.28) go through `muse label`, which already supports arbitrary namespace:value strings with zero format enforcement. Documented the rationale in docs/issues/version-tags-followup.md.
Item 5 (implemented): git-style `tag~N` tilde notation for version tags.
resolve_commit_ref() already had a generic `base~N` regex that recurses into itself to resolve `base`, but `base` resolution never tried version tags -- only HEAD, branch refs, reflog @{N} specs, and literal commit IDs/prefixes. `v1.0.0~2` failed with "Ref not found" even though `v1.0.0` alone *also* failed (a bare version tag never resolved at all -- a more fundamental gap than the ticket described). Added a version-tag lookup strategy to resolve_commit_ref, placed before the exact-commit-ID/prefix fallbacks. Since resolve_commit_ref is the single resolution function shared by `muse describe`, `muse checkout`, and `muse rev-list`'s `A..B` range syntax, this one fix makes all three understand version tags and tag~N notation at once -- confirmed via actual CLI calls, not just the core function. `muse rev-list v0.9.0..v1.0.0` now also works, covering the spirit of the ticket's third example (`muse log v0.2.0..v0.2.0-rc14`) without needing to add range syntax to `log` itself.
Found and fixed a second, pre-existing bug while wiring this up: `checkout.py`'s `_is_commit_ref` detection never recognized `~` at all (not just for version tags -- `HEAD~1` was equally broken), so any tilde ref hit `validate_branch_name`'s rejection of `~` as a forbidden character before ever reaching resolve_commit_ref. Broadened the detection to include any target containing `~`. This in turn surfaced a third bug: resolving `HEAD~N` while ALREADY in detached HEAD state passed an empty branch string into resolve_commit_ref's branch-based HEAD lookup, crashing with an unhandled ValueError (resolve_commit_ref has no concept of checkout.py's separate detached-HEAD state). Fixed by substituting the literal detached commit ID at the call site before tilde resolution, rather than relying on a (nonexistent) branch.
New tests: - tests/test_version_tag_relative_resolution.py: core-level resolve_commit_ref tests (bare tag, tilde~1/~3/beyond-root, nonexistent tag, pre-release tag names) plus CLI integration tests for describe/checkout/rev-list. - tests/test_cmd_checkout.py::TestDetachTildeRef: HEAD~1 from a branch, and the chained detached-HEAD-to-detached-HEAD HEAD~1 case that previously crashed.
Confirmed genuine RED on all of the above (reverted both fixes, 9 of 11 new tests failed, including a raw JSONDecodeError from the detached-HEAD crash) before GREEN with both fixes restored.
Targeted regression suite -- test_cmd_checkout.py, test_cmd_describe.py, test_cmd_describe_version_tags.py, test_cmd_describe_hardening.py, test_cmd_rev_list.py, test_cmd_version_tags.py, test_core_version_tags.py, test_cmd_rev_parse.py, test_version_tag_relative_resolution.py -- all pass (514 passed), zero regressions.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Semantic Changes
37 symbols
Files Changed
+1
~4
1217 in snapshot
0 comments
muse hub commit comment sha256:76a7ec1f3a4bb422eb12c3e2bf84f75bb3f026ca722152cd1ed0e5aec24dd65a --body "your comment"
No comments yet. Be the first to start the discussion.