Skip to main content

worktree_io/git/
local_branch.rs

1use anyhow::{bail, Context, Result};
2use std::path::Path;
3
4/// Detect the current branch of a local (non-bare) repository.
5///
6/// Uses `git rev-parse --abbrev-ref HEAD` and falls back to checking `main`,
7/// `master`, and `develop` in that order.
8///
9/// # Errors
10///
11/// Returns an error if any git command fails to spawn or if the default branch
12/// cannot be determined.
13pub fn detect_local_default_branch(repo: &Path) -> Result<String> {
14    let output = super::git_cmd()
15        .args(["-C"])
16        .arg(repo)
17        .args(["rev-parse", "--abbrev-ref", "HEAD"])
18        .output()
19        .context("Failed to run `git rev-parse --abbrev-ref HEAD`")?;
20
21    if output.status.success() {
22        let branch = String::from_utf8_lossy(&output.stdout).trim().to_string();
23        if !branch.is_empty() && branch != "HEAD" {
24            return Ok(branch);
25        }
26    }
27
28    // Fallback: check common branch names
29    for candidate in ["main", "master", "develop"] {
30        let output = super::git_cmd()
31            .args(["-C"])
32            .arg(repo)
33            .args(["rev-parse", "--verify", &format!("refs/heads/{candidate}")])
34            .output()
35            .context("Failed to run `git rev-parse`")?;
36        if output.status.success() {
37            return Ok(candidate.to_string()); // LLVM_COV_EXCL_LINE
38        }
39    }
40
41    bail!("Could not detect default branch for the local repository"); // LLVM_COV_EXCL_LINE
42}
43
44/// Return `true` if `branch` exists as a local branch in `repo`.
45#[must_use]
46pub fn branch_exists_local(repo: &Path, branch: &str) -> bool {
47    super::git_cmd()
48        .args(["-C"])
49        .arg(repo)
50        .args(["rev-parse", "--verify", &format!("refs/heads/{branch}")])
51        .output()
52        .map(|o| o.status.success())
53        .unwrap_or(false)
54}