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

feat: muse#54 item 3 — muse reflog compact

Adds `muse reflog compact [--branch <name>] [--dry-run] [--json]`: scans a log in storage order (oldest-first, matching how entries are actually appended) and merges each maximal run of 2+ ADJACENT entries sharing an operation category (commit/reset/merge/..., via the categorize_operation() helper lifted from `muse reflog stat` into muse/core/reflog.py so both commands share one definition) into a single summary entry spanning the run — old_id from the run's first entry, new_id/timestamp from its last, author preserved when the whole run shares one author, else "various". The same spirit as `muse rebase --squash` at the commit level: entries outside a qualifying run, and malformed lines, are left untouched; the write is atomic (tmp file + os.replace), following the exact pattern already used by expire_reflog.

Design decision (documented inline in reflog-followup.md): compaction is explicit/on-demand, never automatic on every append_reflog call — reflog entries are the safety-net audit trail for undoing accidental ref movements, so silently collapsing history on write would undermine that guarantee for anyone who hasn't looked at an entry yet.

Covered by tests/test_reflog_compact.py (11 cases: categorize_operation unit tests, core compact_reflog run-merging, different-category non-merging, lone-entry non-compaction, mixed-author -> "various", --dry-run leaves the file untouched, two separate runs split by a differing category both compact independently, plus 3 CLI integration tests for --json/--dry-run/invalid-branch). Confirmed genuine RED by reverting both changed files and re-running (ImportError: compact_reflog doesn't exist), then GREEN with the fix restored plus the full reflog regression suite (138 passed, zero regressions). Live-verified via muse-dev against a disposable /tmp sandbox (dry-run leaves 3 entries intact, real run merges them into 1 "commit (compacted 3 entries)" line).

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

sha256:88a9fd7a7eb0cb829b95c6ba769f831ff0e29fe8336036a93d00730e5e908aff sha
+41 ~10 −2 symbols
4 changed · 1230 in snapshot files
sha256:4913b637c026775a420e96b04793979e0a7929f62bde7b68f41d6b27695f99ba snapshot
+41
symbols added
~10
symbols modified
−2
symbols removed
4
files changed
1230
files in snapshot
0
dead code introduced
Semantic Changes 53 symbols
~ tests/test_reflog_compact.py .py 34 symbols added
+ TestCategorizeOperation class class TestCategorizeOperation L63–68
+ test_prefix_with_parenthetical method method test_prefix_with_parenthetical L67–68
+ test_simple_prefix method method test_simple_prefix L64–65
+ TestCompactReflogCore class class TestCompactReflogCore L71–156
+ test_different_authors_become_various method method test_different_authors_become_various L112–121
+ test_different_categories_not_merged method method test_different_categories_not_merged L90–100
+ test_dry_run_does_not_write method method test_dry_run_does_not_write L123–135
+ test_lone_entry_never_compacted method method test_lone_entry_never_compacted L102–110
+ test_merges_consecutive_same_category_run method method test_merges_consecutive_same_category_run L72–88
+ test_second_run_also_merged method method test_second_run_also_merged L137–156
+ TestReflogCompactCli class class TestReflogCompactCli L159–192
+ test_cli_compact_dry_run_json method method test_cli_compact_dry_run_json L174–187
+ test_cli_compact_json method method test_cli_compact_json L160–172
+ test_cli_invalid_branch_errors method method test_cli_invalid_branch_errors L189–192
+ _commit_file function function _commit_file L44–50
+ _env function function _env L20–21
+ _fake_commit_id function function _fake_commit_id L59–60
+ _init_repo function function _init_repo L28–41
+ _run function function _run L24–25
+ _write_raw_entry function function _write_raw_entry L53–56
+ cli variable variable cli L16–16
+ CliRunner import import CliRunner L11–11
+ Manifest import import Manifest L12–12
+ NULL_COMMIT_ID import import NULL_COMMIT_ID L12–12
+ annotations import import annotations L6–6
+ categorize_operation import import categorize_operation L14–14
+ compact_reflog import import compact_reflog L14–14
+ fake_id import import fake_id L12–12
+ json import import json L8–8
+ logs_dir import import logs_dir L13–13
+ muse_dir import import muse_dir L13–13
+ pathlib import import pathlib L9–9
+ read_reflog import import read_reflog L14–14
+ runner variable variable runner L17–17
~ docs/issues/reflog-followup.md .md 1 symbol added, 1 symbol removed, 2 symbols modified
− Automatic log compaction section 3. Automatic log compaction L43–53
+ Automatic log compaction ✅ IMPLEMENTED section 3. Automatic log compaction ✅ IMPLEMENTED L43–62
~ muse/cli/commands/reflog.py .py 4 symbols added, 1 symbol removed, 8 symbols modified
− _operation_category function function _operation_category L866–877
+ _CompactJson class class _CompactJson L139–145
+ categorize_operation import import categorize_operation L86–86
+ compact_reflog import import compact_reflog L86–86
+ run_compact function function run_compact L680–742
~ muse/core/reflog.py .py 2 symbols added
+ categorize_operation function function categorize_operation L439–450
+ compact_reflog function function compact_reflog L453–585
Files Changed
+1 ~3
1230 in snapshot
← Older Oldest on feat/54-reflog-compact
All commits
Newer → Latest on feat/54-reflog-compact

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:88a9fd7a7eb0cb829b95c6ba769f831ff0e29fe8336036a93d00730e5e908aff --body "your comment"