cgcardona / muse public
blame.md markdown
90 lines 2.7 KB
e0353dfe feat: muse reflog, gc, archive, bisect, blame, worktree, workspace Gabriel Cardona <cgcardona@gmail.com> 6h ago
1 # `muse blame` — line-level attribution for text files
2
3 `muse blame` shows which commit last modified each line of a text file tracked in `state/`. It is the universal, domain-agnostic attribution tool — the core VCS equivalent of `git blame`.
4
5 For domain-specific attribution, see:
6 - `muse midi note-blame` — per-bar attribution in MIDI tracks
7 - `muse code blame` — per-symbol attribution in code files
8
9 ## Usage
10
11 ```bash
12 muse blame README.md
13 muse blame --ref v1.0.0 docs/design.md
14 muse blame --porcelain state/config.toml | jq '.commit_id'
15 muse blame --short 8 src/main.py
16 ```
17
18 ## Options
19
20 | Flag | Default | Description |
21 |------|---------|-------------|
22 | `--ref`, `-r` | HEAD | Commit or branch to blame from |
23 | `--porcelain`, `-p` | false | Emit JSON objects instead of human-readable output |
24 | `--short` | 12 | Length of commit SHA prefix to display |
25
26 ## Output (human-readable)
27
28 ```
29 cccccccc0000 (Test User 2026-03-19) 1 hello world
30 ```
31
32 Columns:
33 - Commit SHA prefix (12 chars by default)
34 - Author name (padded)
35 - Date (`YYYY-MM-DD`)
36 - Line number (right-aligned)
37 - Line content
38
39 ## Output (`--porcelain`)
40
41 One JSON object per line:
42
43 ```json
44 {"lineno": 1, "commit_id": "cccccccc…", "author": "Test User", "committed_at": "2026-03-19T14:22:01+00:00", "message": "initial commit", "content": "hello world"}
45 ```
46
47 ## How attribution works
48
49 The blame algorithm walks the commit graph backwards from the requested ref:
50
51 1. Every line in the file at HEAD is initially attributed to HEAD.
52 2. For each ancestor commit, a unified diff is computed between the ancestor's version and its child's.
53 3. Lines that appear unchanged in both versions are **re-attributed to the ancestor** — the older commit that first introduced them.
54 4. Lines that were added by a commit remain attributed to that commit.
55
56 This is equivalent to Git's blame algorithm for linear histories. For merge commits, the algorithm chooses the first parent to keep attribution clean.
57
58 ## Agent workflows
59
60 ### Find who introduced a bug
61
62 ```bash
63 muse blame --porcelain src/parser.py \
64 | jq 'select(.content | test("legacy_mode")) | .commit_id' \
65 | sort -u
66 ```
67
68 ### Audit a configuration file
69
70 ```bash
71 muse blame config/production.toml
72 ```
73
74 ### Annotate every line with its commit
75
76 ```bash
77 muse blame --porcelain README.md > blame-report.jsonl
78 ```
79
80 ## Limitations
81
82 - Only text files are supported. Binary files (images, MIDI, etc.) should use domain-specific blame commands.
83 - The walk follows the first-parent chain for merge commits. To attribute across both parents, use `muse midi note-blame` or `muse code blame` which are domain-aware.
84
85 ## Exit codes
86
87 | Code | Meaning |
88 |------|---------|
89 | 0 | Success |
90 | 1 | File not found at the specified ref, or ref not found |