gabriel / muse public
Closed #28
filed by gabriel human · 42 days ago

Support .. range syntax in muse log

0 Anchors
Blast radius
Churn 30d
0 Proposals

Context

Issue #27 added .. range syntax to muse diff and noted that muse rev-list already supports it. muse log a..b was deferred because it requires more than arg-parsing sugar — it needs a stop-at walk.

Desired Behavior

muse log dev..feat/x

Show only commits reachable from feat/x but not reachable from dev — i.e. the commits unique to the feature branch. This is the standard meaning of A..B in log context.

Why This Is Different From muse diff

muse diff a..b is pure sugar — split the arg, pass two refs to the existing two-commit diff path.

muse log a..b requires a new walk strategy:

  1. Resolve A and B to commit IDs
  2. Walk from B, collecting commits
  3. Stop (exclude) any commit reachable from A

muse log currently accepts one ref and walks from there to root. It has no exclude/stop-at mechanism. muse rev-list already implements this via _parse_range_ref and ancestor exclusion — that logic needs to be ported or shared with log.

Implementation Sketch

File Change
muse/cli/commands/log.py Detect .. in the ref positional, split into (exclude_ref, start_ref), pass exclude_commit_id to the walk
muse/core/commits.py (or equivalent) Add a walk_excluding_ancestors(start, exclude) helper, or reuse the one already in rev_list.py

muse rev-list has the ancestor-exclusion walk at _ancestors_of — worth extracting to a shared utility rather than duplicating.

Acceptance Criteria

  • muse log dev..feat/x shows only commits on feat/x not reachable from dev
  • muse log dev..feat/x --json returns the correct filtered commit list
  • muse log feat/x (no ..) still works as before
  • _ancestors_of or equivalent is extracted to a shared location rather than duplicated between log and rev-list
Activity1
gabriel opened this issue 42 days ago
gabriel 42 days ago

Implemented in MP #4 (merged). The stop-at walk was added to muse/cli/commands/log.py using muse.core.graph.ancestor_ids to compute the exclude set, then filtering raw commits before display. TDD coverage in tests/test_log_dotdot_range.py — 8 tests (LOG_DR1–LOG_DR8) covering: plain ref still works, feature-only commits shown, empty when same ref, JSON schema, -n limit, unknown exclude ref errors, unknown include ref errors, and raw commit IDs as refs. All 8 pass.

closed this issue 42 days ago