# `Minga.Git.Repo`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/git/repo.ex#L1)

Per-repository GenServer that owns repo-wide git state.

One `Git.Repo` exists per git root, registered via `Minga.Git.Repo.Registry`.
It caches the working tree status (staged, unstaged, untracked, conflict files),
the current branch name, and ahead/behind counts relative to the upstream.

## Refresh strategy

Event-driven, not polling. Git.Repo starts its own `file_system` watcher on
the `.git/` directory and filters for changes to `index` (stage/unstage/commit)
and `HEAD` (branch switch, new commits). A fallback refresh fires on
`:buffer_saved` events to catch cases where FileWatcher misses changes.

## Event publication

Publishes `:git_status_changed` on the event bus whenever status changes.
The status panel, modeline, and other consumers subscribe to this event
for live updates.

# `start_opt`

```elixir
@type start_opt() ::
  {:git_root, String.t()}
  | {:project_root, String.t() | nil}
  | {:events_registry, Minga.Events.registry()}
```

Options for starting a Git.Repo process.

# `status_snapshot`

```elixir
@type status_snapshot() :: Minga.Git.Repo.StatusSnapshot.t()
```

Cached status entries plus the path they are relative to.

# `summary`

```elixir
@type summary() :: %{
  branch: String.t() | nil,
  ahead: non_neg_integer(),
  behind: non_neg_integer(),
  staged_count: non_neg_integer(),
  unstaged_count: non_neg_integer(),
  untracked_count: non_neg_integer(),
  conflict_count: non_neg_integer(),
  last_commit_message: String.t(),
  stash_count: non_neg_integer()
}
```

Summary of repo status for display.

# `t`

```elixir
@type t() :: %Minga.Git.Repo{
  ahead: non_neg_integer(),
  awaiting_refresh: [GenServer.from()],
  behind: non_neg_integer(),
  branch: String.t() | nil,
  debounce_ref: reference() | nil,
  entries: [Minga.Git.StatusEntry.t()],
  events_registry: Minga.Events.registry(),
  git_root: String.t(),
  last_commit_message: String.t(),
  profile: Minga.Git.Repo.Profile.t() | nil,
  project_root: String.t() | nil,
  refresh_pending?: boolean(),
  refresh_task: refresh_task() | nil,
  stash_count: non_neg_integer(),
  watcher_pid: pid() | nil
}
```

Git.Repo internal state.

# `await_refresh`

```elixir
@spec await_refresh(GenServer.server()) :: :ok
```

Blocks until the repo has no in-flight or pending refresh work.

# `branch`

```elixir
@spec branch(GenServer.server()) :: String.t() | nil
```

Returns the current branch name.

# `cached_status_for_path`

```elixir
@spec cached_status_for_path(String.t()) :: {:ok, status_snapshot()} | :not_tracked
```

Returns cached status for the tracked repo containing `path`, without shelling out to git.

# `child_spec`

```elixir
@spec child_spec([start_opt()]) :: Supervisor.child_spec()
```

Returns the child spec for supervision.

# `ensure_started`

```elixir
@spec ensure_started(String.t(), String.t() | nil, Minga.Events.registry()) ::
  {:ok, pid()} | {:error, term()}
```

Ensures a Git.Repo process exists for the given git root.

Returns `{:ok, pid}` if one already exists or was started successfully,
or `{:error, reason}` if it couldn't be started.

# `lookup`

```elixir
@spec lookup(String.t()) :: pid() | nil
```

Looks up the Git.Repo process for a git root.

Returns the pid or nil if no repo is tracked for that root.

# `refresh`

```elixir
@spec refresh(GenServer.server()) :: :ok
```

Forces a status refresh. Used after staging/committing operations.

# `start_link`

```elixir
@spec start_link([start_opt()]) :: GenServer.on_start()
```

Starts a Git.Repo for the given git root.

# `status`

```elixir
@spec status(GenServer.server()) :: [Minga.Git.StatusEntry.t()]
```

Returns the cached status entries.

# `status_snapshot`

```elixir
@spec status_snapshot(GenServer.server()) :: status_snapshot()
```

Returns the cached status entries with the path they are relative to.

# `summary`

```elixir
@spec summary(GenServer.server()) :: summary()
```

Returns a summary of the repo status.

---

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