Skip to main content

nb_api/
git.rs

1//! Git repository detection helpers.
2//!
3//! Shared between nb-api and nb-mcp-server (paths.rs).
4
5use std::path::PathBuf;
6
7/// Derive the notebook name from the current Git repository.
8///
9/// Returns the directory name of the master repository (not the worktree).
10/// Used as a fallback when no explicit notebook name is configured.
11pub fn derive_git_notebook_name() -> Option<String> {
12    let current_root = git_rev_parse(&["--show-toplevel"])?;
13    let git_common_dir = git_rev_parse(&["--git-common-dir"])?;
14    let git_common_dir = if git_common_dir.is_relative() {
15        current_root.join(&git_common_dir)
16    } else {
17        git_common_dir
18    };
19    let git_common_dir = git_common_dir.canonicalize().ok()?;
20    let master_root = if git_common_dir.file_name().is_some_and(|n| n == ".git") {
21        git_common_dir.parent()?.to_path_buf()
22    } else {
23        return None;
24    };
25    master_root
26        .file_name()
27        .and_then(|name| name.to_str())
28        .map(|name| name.to_string())
29}
30
31/// Run `git rev-parse` with the given arguments and return the output as a path.
32///
33/// Returns `None` if git is not available, the command fails, or the output is empty.
34pub fn git_rev_parse(args: &[&str]) -> Option<PathBuf> {
35    let output = std::process::Command::new("git")
36        .args(["rev-parse"])
37        .args(args)
38        .output()
39        .ok()?;
40    if !output.status.success() {
41        return None;
42    }
43    let stdout = String::from_utf8(output.stdout).ok()?;
44    let value = stdout.trim();
45    if value.is_empty() {
46        return None;
47    }
48    Some(PathBuf::from(value))
49}