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

Configuration for the git CLI wrapper.

Holds the path to the git binary, working directory, environment variables,
and timeout settings used when executing git commands.

## Controlling identity, dates, and the index

Per-call author/committer identity and dates, and the index file, are set
through the `:env` and `:extra_config` fields rather than dedicated options,
since git reads them from the environment and per-invocation config:

  * Author/committer **dates** (note `commit --date` sets only the author date,
    while the committer date is separate):

        Git.Config.new(env: [
          {"GIT_AUTHOR_DATE", "2020-01-01T00:00:00"},
          {"GIT_COMMITTER_DATE", "2020-01-01T00:00:00"}
        ])

  * Author/committer **identity**, either via the environment or, without
    mutating repo config, via `-c` using `:extra_config`:

        Git.Config.new(extra_config: [
          {"user.name", "A U Thor"},
          {"user.email", "author@example.com"}
        ])

  * A scratch **index** for building commits off to the side (pairs with
    `write_tree/1` and `commit_tree/1`):

        Git.Config.new(env: [{"GIT_INDEX_FILE", "/tmp/scratch.index"}])

Any `GIT_*` variable can be passed through `:env`; entries there override the
built-in defaults.

# `runner`

```elixir
@type runner() :: :system_cmd | :forcola | module()
```

How git commands are executed.

  * `:forcola` - the default, `Git.Runner.Forcola`, which runs git in its own
    process group and kills the whole group on timeout, so a timed-out command
    and its children (hooks, credential helpers, transports) do not leak.
    Requires the optional `:forcola` dependency and a supported platform
    (macOS or Linux); it falls back to `:system_cmd` when forcola is not
    loaded (for example on Windows or when the dependency is absent).
  * `:system_cmd` - `System.cmd/3` via `Git.Runner.SystemCmd`. No extra
    dependency and works everywhere, but a timed-out command abandons the OS
    process rather than killing it.
  * any module implementing the `Git.Runner` behaviour.

# `t`

```elixir
@type t() :: %Git.Config{
  binary: String.t(),
  env: [{String.t(), String.t()}],
  extra_config: [{String.t(), String.t()}],
  runner: runner(),
  timeout: pos_integer(),
  working_dir: String.t() | nil
}
```

# `base_args`

```elixir
@spec base_args(t()) :: [String.t()]
```

Returns the base arguments prepended to every git command.

Emits a `-c key=value` pair for each entry in the config's `:extra_config`, so
a caller can set config per-invocation (for example `merge.conflictStyle` or
`commit.gpgsign`) without mutating repo config. Returns `[]` when
`:extra_config` is empty.

# `cmd_opts`

```elixir
@spec cmd_opts(t()) :: keyword()
```

Builds the options keyword list for `System.cmd/3`.

Includes `:cd`, `:env`, and `:stderr_to_stdout` based on the config. The
environment always defaults `GIT_TERMINAL_PROMPT=0` so an auth-required
command fails fast instead of hanging on a credential prompt; entries in the
config's `:env` override the defaults on a key collision.

# `find_binary`

```elixir
@spec find_binary() :: String.t()
```

Finds the git binary on the system.

Checks the `GIT_PATH` environment variable first, then falls back to
`System.find_executable("git")`.

Raises if git cannot be found.

# `new`

```elixir
@spec new(keyword()) :: t()
```

Creates a new `Git.Config` struct.

## Options

  * `:binary` - path to the git executable (default: auto-detected)
  * `:working_dir` - working directory for git commands (default: `nil`, uses current directory)
  * `:env` - list of `{key, value}` tuples for environment variables (default: `[]`)
  * `:timeout` - command timeout in milliseconds (default: `30000`)
  * `:runner` - how commands are executed (default: `:forcola`).
    See the `t:runner/0` type.
  * `:extra_config` - list of `{key, value}` tuples emitted as `git -c key=value`
    before every subcommand, to set config per-invocation without mutating repo
    config (default: `[]`)

## Examples

    iex> config = Git.Config.new()
    iex> String.ends_with?(config.binary, "git")
    true

    iex> config = Git.Config.new(working_dir: "/tmp", timeout: 10_000)
    iex> config.working_dir
    "/tmp"
    iex> config.timeout
    10_000

    iex> config = Git.Config.new(runner: :forcola)
    iex> config.runner
    :forcola

    iex> config = Git.Config.new(extra_config: [{"merge.conflictStyle", "diff3"}])
    iex> Git.Config.base_args(config)
    ["-c", "merge.conflictStyle=diff3"]

---

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