# `Git.History`
[🔗](https://github.com/joshrotenberg/git_wrapper_ex/blob/main/lib/git/history.ex#L1)

Higher-level history query helpers that compose lower-level `Git` functions.

All functions accept an optional keyword list. Use `:config` to specify the
repository via a `Git.Config` struct; when omitted a default config is built
from the environment.

# `ancestor?`

```elixir
@spec ancestor?(String.t(), String.t(), keyword()) ::
  {:ok, boolean()} | {:error, term()}
```

Checks whether `ref1` is an ancestor of `ref2`.

Runs `git merge-base --is-ancestor ref1 ref2` directly.

## Options

  * `:config` - a `Git.Config` struct

## Examples

    {:ok, true} = Git.History.ancestor?("v1.0.0", "main")

# `changelog`

```elixir
@spec changelog(String.t(), String.t(), keyword()) ::
  {:ok,
   %{
     features: [Git.Commit.t()],
     fixes: [Git.Commit.t()],
     other: [Git.Commit.t()]
   }}
  | {:error, term()}
```

Generates a changelog-style grouping of commits between two refs.

Commits are grouped by conventional commit type prefix (`feat:`, `fix:`,
`docs:`, etc.). Commits without a recognized prefix land in `:other`.

## Options

  * `:config` - a `Git.Config` struct

## Examples

    {:ok, changelog} = Git.History.changelog("v1.0.0", "v2.0.0")
    changelog.features  #=> [%Git.Commit{...}, ...]
    changelog.fixes     #=> [%Git.Commit{...}, ...]

# `commits_between`

```elixir
@spec commits_between(String.t(), String.t(), keyword()) ::
  {:ok, [Git.Commit.t()]} | {:error, term()}
```

Returns commits between two refs (tags, branches, SHAs).

Uses `git log ref1..ref2` under the hood.

## Options

  * `:config` - a `Git.Config` struct

## Examples

    {:ok, commits} = Git.History.commits_between("v1.0.0", "v2.0.0")

# `contributors`

```elixir
@spec contributors(keyword()) ::
  {:ok,
   [%{name: String.t(), email: String.t(), commit_count: non_neg_integer()}]}
  | {:error, term()}
```

Returns unique contributors from the commit log.

Each contributor is a map with `:name`, `:email`, and `:commit_count` keys,
deduplicated by email address.

## Options

  * `:config` - a `Git.Config` struct
  * `:path` - limit to commits touching files under this path
  * `:since` - limit to commits after this date (e.g., `"2025-01-01"`)

## Examples

    {:ok, contributors} = Git.History.contributors(since: "2025-01-01")

# `file_history`

```elixir
@spec file_history(
  String.t(),
  keyword()
) :: {:ok, [Git.Commit.t()]} | {:error, term()}
```

Returns commits that touched a specific file.

## Options

  * `:config` - a `Git.Config` struct
  * `:max_count` - limit the number of commits returned

## Examples

    {:ok, commits} = Git.History.file_history("lib/git.ex")

# `files_changed_since`

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

Lists files changed since a given ref.

Uses `git diff --name-only <ref>` under the hood and splits the result into
a list of file paths.

## Options

  * `:config` - a `Git.Config` struct

## Examples

    {:ok, files} = Git.History.files_changed_since("v1.0.0")

---

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