worktree_io/git/
branch.rs1use anyhow::{bail, Context, Result};
2use std::path::Path;
3use std::process::Command;
4
5pub fn detect_default_branch(bare: &Path) -> Result<String> {
6 let output = Command::new("git")
7 .args(["-C"])
8 .arg(bare)
9 .args(["symbolic-ref", "refs/remotes/origin/HEAD"])
10 .output()
11 .context("Failed to run `git symbolic-ref`")?;
12
13 if output.status.success() {
14 let full = String::from_utf8_lossy(&output.stdout);
15 if let Some(branch) = full.trim().strip_prefix("refs/remotes/origin/") {
16 return Ok(branch.to_string());
17 }
18 }
19
20 let output = Command::new("git")
21 .args(["-C"])
22 .arg(bare)
23 .args(["remote", "show", "origin"])
24 .output()
25 .context("Failed to run `git remote show origin`")?;
26
27 if output.status.success() {
28 let text = String::from_utf8_lossy(&output.stdout);
29 for line in text.lines() {
30 let line = line.trim();
31 if let Some(branch) = line.strip_prefix("HEAD branch: ") {
32 return Ok(branch.to_string()); }
34 }
35 }
36
37 for candidate in ["main", "master", "develop"] {
38 let output = Command::new("git")
39 .args(["-C"])
40 .arg(bare)
41 .args([
42 "rev-parse",
43 "--verify",
44 &format!("refs/remotes/origin/{candidate}"),
45 ])
46 .output()
47 .context("Failed to run `git rev-parse`")?;
48 if output.status.success() {
49 return Ok(candidate.to_string()); }
51 }
52
53 bail!("Could not detect default branch for the repository"); }
55
56pub fn branch_exists_remote(bare: &Path, branch: &str) -> bool {
57 Command::new("git")
58 .args(["-C"])
59 .arg(bare)
60 .args([
61 "rev-parse",
62 "--verify",
63 &format!("refs/remotes/origin/{branch}"),
64 ])
65 .output()
66 .map(|o| o.status.success())
67 .unwrap_or(false)
68}