# `Exgit.Diff`
[🔗](https://github.com/ivarvong/exgit/blob/v0.1.0/lib/exgit/diff.ex#L1)

Compare two git trees and return a list of changes.

Changes are returned as maps with explicit keys so callers can pattern
match on the operation, path, modes, and SHAs:

    %{op: :added,             path: String.t(), new_mode: String.t(), new_sha: binary()}
    %{op: :removed,           path: String.t(), old_mode: String.t(), old_sha: binary()}
    %{op: :modified,          path: String.t(), old_mode: String.t(), new_mode: String.t(),
                              old_sha: binary(), new_sha: binary()}
    %{op: :mode_changed,      path: String.t(), old_mode: String.t(), new_mode: String.t(),
                              old_sha: binary(), new_sha: binary()}
    %{op: :submodule_change,  path: String.t(), old_sha: binary(), new_sha: binary()}
    %{op: :type_changed,      path: String.t(), old_mode: String.t(), new_mode: String.t(),
                              old_sha: binary(), new_sha: binary()}

## Options

  * `:prefix` — path prefix for the produced change entries. Default `""`.
  * `:max_depth` — maximum tree recursion depth. Protects against a
    hostile tree with a circular reference or a pathological nesting
    that would overflow the stack. Default 256 (git itself caps
    around 4096).
  * `:max_changes` — cap the number of change entries. Prevents
    a single `Diff.trees` call from producing millions of entries
    on a hostile input. Default `nil` (unbounded; caller takes
    responsibility).

## Defense in depth

`Diff.trees/4` is the one path that walks arbitrary (possibly
remote-sourced) tree graphs recursively. It must not overflow the
stack or loop forever on a tree object that references itself
(directly or indirectly). The `:max_depth` cap is the guard; a
tree that exceeds it returns `{:error, {:max_depth_exceeded, n}}`
so callers can distinguish "legitimately deep" from "hostile".

# `change`

```elixir
@type change() :: %{:op =&gt; atom(), :path =&gt; String.t(), optional(atom()) =&gt; term()}
```

# `trees`

```elixir
@spec trees(term(), binary() | nil, binary() | nil, keyword()) ::
  {:ok, [change()]} | {:error, term()}
```

---

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