# Config

> Merged config reads and repository-local writes through ConfigHandle.

Configuration in grit-lib follows Git’s cascade (system, global, local, worktree, and environment overrides). Prefer `Repository::config_handle` for hot paths: it returns `ConfigHandle`, which reads the same merged snapshot as `Repository::config` and can update the repository-local file.

## Loading outside a handle

[`ConfigSet::load`](https://docs.rs/grit-lib/latest/grit_lib/config/struct.ConfigSet.html) parses the cascade from disk given an [`Environment`](https://docs.rs/grit-lib/latest/grit_lib/config/environment/struct.Environment.html) and optional git directory. The library does not read `std::env` during load — embedders pass variables explicitly (see [Embedding](https://grit-scm.com/docs/library/embedding/index.md) and [Repository](https://grit-scm.com/docs/library/repository/index.md)).

## Local writes

`ConfigHandle::set_local` writes one key to the repository-local config (or `commondir/config` for linked worktrees without a per-worktree config file), then reloads the in-memory snapshot on the open `Repository`.

## Example

```rust
//! Read and write repository-local config through [`ConfigHandle`](https://grit-scm.com/docs/library/config/grit_lib::config::ConfigHandle/index.md).
//!
//! Source for the library guide "Config" page (included in the docs site).

use grit_lib::config::environment::RepositoryOptions;
use grit_lib::repo::Repository;
use std::path::{Path, PathBuf};

fn open_repo(root: &Path) -> Result<Repository, grit_lib::error::Error> {
    let git_dir = if root.join(".git").is_dir() {
        root.join(".git")
    } else {
        root.to_path_buf()
    };
    let work_tree = if root.join(".git").is_dir() {
        Some(root)
    } else {
        None
    };
    let mut opts = RepositoryOptions::from_process();
    if let Some(wt) = work_tree {
        opts = opts.with_work_tree(wt);
    }
    Repository::open(&git_dir, &opts)
}

fn main() -> Result<(), grit_lib::error::Error> {
    let root = std::env::args()
        .nth(1)
        .map(PathBuf::from)
        .or_else(|| std::env::current_dir().ok())
        .ok_or_else(|| grit_lib::error::Error::Message("missing repository path".into()))?;
    let repo = open_repo(&root)?;

    repo.config_handle()
        .set_local("user.name", "Library Guide Config")?;

    let name = repo.config_handle().get("user.name")?.unwrap_or_default();
    println!("user.name={name}");

    let format = repo
        .config_handle()
        .get("core.repositoryformatversion")?
        .unwrap_or_default();
    println!("core.repositoryformatversion={format}");

    Ok(())
}
```

```bash
cargo run --bin guide_config /path/to/repo
git -C /path/to/repo config user.name
```

The integration test checks the printed `user.name` against `git config user.name`.
