# `MixAffected.ChangedFiles`
[🔗](https://github.com/mnox/mix_affected/blob/v0.1.0/lib/mix_affected/changed_files.ex#L1)

Where a change set comes from: `--files <path|->` or `--base <git-ref>`.

From git, the change set is the union of

  * `git diff --name-only --no-relative --no-renames <ref>...HEAD` (committed on the branch)
  * `git diff --name-only --no-relative --no-renames HEAD` (staged and unstaged)
  * `git ls-files --others --exclude-standard --full-name -- :/` (untracked)

All three cover the whole repository, not only the project directory: a
`diff.relative` config is overridden and untracked files are listed from
the top level, so a project in a subdirectory still sees changes beside it.

`--no-renames` makes a moved file show as delete + add, so its old path
forces a full run as an unmapped file. Paths are made relative to the
project root (git reports them relative to the repository top level); a
changed file outside the project root stays absolute, which the classifier
turns into a full run.

The ref is checked before any diff: an empty or blank ref (git would read
`...HEAD` as an empty range), an option-like ref (git would read it as an
option, e.g. `--output=<file>`) and a ref that does not resolve to a commit
are errors, never an empty change set. Every diff ends its revisions with
`--`, so a ref is never read as a path. A ref with no merge base with
`HEAD` (an unrelated history, or a shallow clone missing it) is an error.

# `from_files`

```elixir
@spec from_files(String.t()) :: {:ok, [String.t()]} | {:error, String.t()}
```

Reads newline-separated paths from `path`, or stdin when `path` is `"-"`.

# `from_git`

```elixir
@spec from_git(Path.t(), String.t()) :: {:ok, [String.t()]} | {:error, String.t()}
```

The change set of the working tree at `root` against `ref`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
