gabriel / muse public
feat patch feat/54-tag-reflog #1 / 1
AI Agent gabriel · 1 day ago · Oct 21, 2026 · Diff

feat: reflog entries for tag/release creation, muse reflog --tag (muse#54 item 5)

`muse tag add` and `muse release add` moved refs/tags/*-equivalent pointers with zero reflog trace -- exactly the gap this item describes.

Added a parallel reflog namespace for tags (.muse/logs/refs/tags/, mirroring .muse/logs/refs/heads/ for branches) with its own append_tag_reflog()/read_tag_reflog() pair in muse/core/reflog.py. Deliberately does NOT also write to the HEAD log the way append_reflog() does for branches: tagging doesn't move HEAD, so it has no business appearing in `muse reflog`'s default view.

`muse tag add` logs every call (new tag -- old_id=None -- or a re-point -- old_id=the previous commit_id), since `tag add`'s own semantics already allow silently repointing an existing tag to a different commit (confirmed by reading run_add: commit_id is always the newly-resolved ref, "existing" only preserves created_at/author/message). `muse release add` only ever creates (it already rejects an existing release for the same tag before reaching this point), so always logs old_id=None.

`muse reflog --tag <name>` reads the new namespace, mutually exclusive with --branch/--all (mixing ref-type filters doesn't make sense). Follows the exact same read_reflog()-based JSON contract as the branch case, just pointed at refs/tags/<name> instead of refs/heads/<name>.

New tests/test_tag_reflog.py (8): new tag logs a creation entry (old_id=all-zeros), re-pointing an existing tag logs both the old and new commit, tagging never pollutes the HEAD/branch reflog, a new release logs a creation entry, a draft release's operation notes "(draft)", `reflog --tag` returns the tag's own history, --tag + --branch together is rejected, and a tag that was never created returns an empty (not erroring) result. Confirmed genuine RED (7/8 failed -- ImportError on read_tag_reflog, unrecognized --tag flag) before GREEN with the fix restored.

Targeted regression suite -- the new file plus test_core_reflog.py, test_cmd_reflog.py, test_cmd_reflog_hardening.py, test_cmd_version_tags.py, test_release.py, test_cmd_release_hardening.py, test_release_tag_crosslink.py -- all pass (409 passed), zero regressions.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

sha256:5b6ba190e9a1ab3db0166f2ff1b4881ccdcea6449081b77deccc4910954f734b sha
+34 ~17 symbols
7 changed · 1223 in snapshot files
sha256:04c4f52eaee5e7a713e1786b6ad0b0a605e168b4f5e9aeda775439d5827839cd snapshot
+34
symbols added
~17
symbols modified
7
files changed
1223
files in snapshot
0
dead code introduced
Semantic Changes 51 symbols
~ tests/test_tag_reflog.py .py 26 symbols added
+ TestReflogTagFlag class class TestReflogTagFlag L139–164
+ test_reflog_tag_and_branch_mutually_exclusive method method test_reflog_tag_and_branch_mutually_exclusive L152–156
+ test_reflog_tag_empty_when_tag_never_created method method test_reflog_tag_empty_when_tag_never_created L158–164
+ test_reflog_tag_shows_tag_history method method test_reflog_tag_shows_tag_history L140–150
+ TestReleaseAddReflog class class TestReleaseAddReflog L115–136
+ test_draft_release_notes_draft_in_operation method method test_draft_release_notes_draft_in_operation L129–136
+ test_new_release_logs_creation_entry method method test_new_release_logs_creation_entry L116–127
+ TestTagAddReflog class class TestTagAddReflog L72–112
+ test_does_not_appear_in_head_reflog method method test_does_not_appear_in_head_reflog L102–112
+ test_new_tag_logs_creation_entry method method test_new_tag_logs_creation_entry L73–85
+ test_repointed_tag_logs_old_and_new_commit method method test_repointed_tag_logs_old_and_new_commit L87–100
+ _env function function _env L22–23
+ _init_repo function function _init_repo L30–43
+ _make_commit function function _make_commit L46–69
+ _run function function _run L26–27
+ cli variable variable cli L18–18
+ CliRunner import import CliRunner L14–14
+ Manifest import import Manifest L15–15
+ annotations import import annotations L8–8
+ datetime import import datetime L10–10
+ fake_id import import fake_id L15–15
+ json import import json L11–11
+ muse_dir import import muse_dir L16–16
+ pathlib import import pathlib L12–12
+ ref_path import import ref_path L16–16
+ runner variable variable runner L19–19
~ muse/cli/commands/reflog.py .py 1 symbol added, 7 symbols modified
+ read_tag_reflog import import read_tag_reflog L83–83
~ run
~ muse/cli/commands/release.py .py 1 symbol modified
~ muse/cli/commands/tag.py .py 1 symbol added, 1 symbol modified
+ append_tag_reflog import import append_tag_reflog L94–94
~ muse/core/paths.py .py 2 symbols added
+ reflog_tag_path function function reflog_tag_path L239–241
+ reflog_tags_dir function function reflog_tags_dir L229–237
~ muse/core/reflog.py .py 4 symbols added, 3 symbols modified
+ append_tag_reflog function function append_tag_reflog L161–198
+ _reflog_tag_path import import _reflog_tag_path L60–60
+ _reflog_tags_dir import import _reflog_tags_dir L60–60
+ read_tag_reflog function function read_tag_reflog L289–325
Files Changed
+1 ~6
1223 in snapshot
← Older Oldest on feat/54-tag-reflog
All commits
Newer → Latest on feat/54-tag-reflog

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:5b6ba190e9a1ab3db0166f2ff1b4881ccdcea6449081b77deccc4910954f734b --body "your comment"