Mutare.Changes (mutare v0.4.3)

Copy Markdown View Source

Source lines changed versus a git ref — the basis for mix mutare --since, the CI mode that mutation-tests only what a branch touched.

Scoping is per-line, not per-file: a one-line edit to a large module mutates only that line, not the whole file. The changed lines are fed to :only_lines (the same site filter --line uses), so a --since run and a --line run share all the downstream machinery.

"Changed" means what the branch changed: lines differing between the working tree and the point where HEAD forked from the ref (their merge base), plus every line of an untracked .ex file. Commits the ref gained after the fork are not the branch's changes and are not included.

Summary

Functions

Lines changed under root versus ref, as a set of {relative_path, line} pairs on the new side of the diff (the lines that now exist to be mutated).

Functions

since(root, ref)

@spec since(Path.t(), String.t()) :: {:ok, MapSet.t()} | {:error, String.t()}

Lines changed under root versus ref, as a set of {relative_path, line} pairs on the new side of the diff (the lines that now exist to be mutated).

The diff runs from the merge base of ref and HEAD to the working tree, so it holds the branch's committed and uncommitted changes and nothing ref gained after the branch forked — what a pull request's diff shows. Untracked files that .gitignore does not exclude are new relative to any ref, so every line of each untracked .ex file is included, as git diff reports a newly added file. Only .ex files, because only those are discovered for mutation; reading other untracked files would cost time and add nothing.

Uses git diff -U0 --relative, run with root as the working dir, so paths are scoped to and relative to root. The diff command disables presentation/user hooks and pins prefixes because the output is parsed, and turns off core.quotePath so a non-ASCII pathname is returned verbatim rather than octal-escaped. -U0 drops context lines so only genuinely-added lines land in the set; pure deletions contribute nothing (their file drops out entirely if it has no other changes). Returns {:error, detail} if git fails (no repo, bad ref, git missing) or finds no merge base (unrelated histories, or a shallow clone missing the fork point).