Skip to main content

worktree_io/git/
local_branch.rs

1use anyhow::{bail, Context, Result};
2use std::path::Path;
3use std::process::Command;
4
5/// Detect the current branch of a local (non-bare) repository.
6pub fn detect_local_default_branch(repo: &Path) -> Result<String> {
7    let output = Command::new("git")
8        .args(["-C"])
9        .arg(repo)
10        .args(["rev-parse", "--abbrev-ref", "HEAD"])
11        .output()
12        .context("Failed to run `git rev-parse --abbrev-ref HEAD`")?;
13
14    if output.status.success() {
15        let branch = String::from_utf8_lossy(&output.stdout).trim().to_string();
16        if !branch.is_empty() && branch != "HEAD" {
17            return Ok(branch);
18        }
19    }
20
21    // Fallback: check common branch names
22    for candidate in ["main", "master", "develop"] {
23        let output = Command::new("git")
24            .args(["-C"])
25            .arg(repo)
26            .args(["rev-parse", "--verify", &format!("refs/heads/{candidate}")])
27            .output()
28            .context("Failed to run `git rev-parse`")?;
29        if output.status.success() {
30            return Ok(candidate.to_string()); // LLVM_COV_EXCL_LINE
31        }
32    }
33
34    bail!("Could not detect default branch for the local repository"); // LLVM_COV_EXCL_LINE
35}
36
37/// Check whether a local branch exists in a non-bare repository.
38pub fn branch_exists_local(repo: &Path, branch: &str) -> bool {
39    Command::new("git")
40        .args(["-C"])
41        .arg(repo)
42        .args(["rev-parse", "--verify", &format!("refs/heads/{branch}")])
43        .output()
44        .map(|o| o.status.success())
45        .unwrap_or(false)
46}