ytil_git/
repo.rs

1use std::path::Path;
2use std::path::PathBuf;
3
4use color_eyre::eyre::Context as _;
5use color_eyre::eyre::ContextCompat as _;
6use color_eyre::eyre::eyre;
7use git2::Repository;
8
9/// Discover the Git repository containing `path` by walking
10/// parent directories upward until a repo root is found.
11///
12/// # Errors
13/// - If the path is not inside a Git repository.
14pub fn discover(path: &Path) -> color_eyre::Result<Repository> {
15    Repository::discover(path).wrap_err_with(|| eyre!("error discovering repo | path={}", path.display()))
16}
17
18/// Absolute working tree root path for repository
19///
20/// Derived from [`Repository::commondir`] with any trailing `.git` removed (non‑bare repos).
21/// Bare repositories return their directory path unchanged.
22pub fn get_root(repo: &Repository) -> PathBuf {
23    repo.commondir()
24        .components()
25        .filter(|c| c.as_os_str() != ".git")
26        .collect()
27}
28
29/// Computes the relative path from the repository root to the given absolute path.
30///
31/// # Errors
32/// - If the repository does not have a working directory (bare repository).
33/// - If the provided path is not within the repository's working directory.
34pub fn get_relative_path_to_repo(path: &Path, repo: &Repository) -> color_eyre::Result<PathBuf> {
35    let repo_workdir = repo.workdir().wrap_err_with(|| {
36        format!(
37            "error getting repository working directory | repo={:?}",
38            repo.path().display()
39        )
40    })?;
41    Ok(Path::new("/").join(path.strip_prefix(repo_workdir)?))
42}