diff options
Diffstat (limited to 'makima/src/daemon/worktree/manager.rs')
| -rw-r--r-- | makima/src/daemon/worktree/manager.rs | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/makima/src/daemon/worktree/manager.rs b/makima/src/daemon/worktree/manager.rs index ff0e9e7..d370828 100644 --- a/makima/src/daemon/worktree/manager.rs +++ b/makima/src/daemon/worktree/manager.rs @@ -128,8 +128,30 @@ impl WorktreeManager { /// Detect the default branch of a repository. /// Tries to find HEAD's target, falling back to common branch names. + /// Works for both regular and bare repositories. pub async fn detect_default_branch(&self, repo_path: &Path) -> Result<String, WorktreeError> { - // Try to get the branch that HEAD points to + tracing::debug!("Detecting default branch for repo: {}", repo_path.display()); + + // First, try to read HEAD directly (works for bare repos) + // In bare repos, HEAD is a symbolic ref to the default branch + let output = Command::new("git") + .args(["symbolic-ref", "HEAD", "--short"]) + .current_dir(repo_path) + .output() + .await?; + + if output.status.success() { + let branch = String::from_utf8_lossy(&output.stdout).trim().to_string(); + if !branch.is_empty() { + tracing::debug!("Detected default branch from HEAD: {}", branch); + return Ok(branch); + } + } else { + let stderr = String::from_utf8_lossy(&output.stderr); + tracing::debug!("symbolic-ref HEAD failed: {}", stderr.trim()); + } + + // Try to get the branch that origin/HEAD points to (for regular clones) let output = Command::new("git") .args(["symbolic-ref", "refs/remotes/origin/HEAD", "--short"]) .current_dir(repo_path) @@ -141,11 +163,12 @@ impl WorktreeManager { // Remove "origin/" prefix if present let branch = branch.strip_prefix("origin/").unwrap_or(&branch).to_string(); if !branch.is_empty() { + tracing::debug!("Detected default branch from origin/HEAD: {}", branch); return Ok(branch); } } - // Try common branch names + // Try common branch names in refs/heads (works for bare and regular repos) for branch in ["main", "master", "develop", "trunk"] { let output = Command::new("git") .args(["rev-parse", "--verify", &format!("refs/heads/{}", branch)]) @@ -154,11 +177,12 @@ impl WorktreeManager { .await?; if output.status.success() { + tracing::debug!("Detected default branch from refs/heads: {}", branch); return Ok(branch.to_string()); } } - // Fall back to getting the current branch + // Fall back to getting the current branch (for regular repos) let output = Command::new("git") .args(["rev-parse", "--abbrev-ref", "HEAD"]) .current_dir(repo_path) @@ -168,12 +192,41 @@ impl WorktreeManager { if output.status.success() { let branch = String::from_utf8_lossy(&output.stdout).trim().to_string(); if !branch.is_empty() && branch != "HEAD" { + tracing::debug!("Detected default branch from rev-parse: {}", branch); + return Ok(branch); + } + } + + // Final fallback: list all branches and pick the first one + let output = Command::new("git") + .args(["for-each-ref", "--format=%(refname:short)", "refs/heads/", "--count=1"]) + .current_dir(repo_path) + .output() + .await?; + + if output.status.success() { + let branch = String::from_utf8_lossy(&output.stdout).trim().to_string(); + if !branch.is_empty() { + tracing::warn!("Using first available branch as fallback: {}", branch); return Ok(branch); } } + // Log what branches exist for debugging + let output = Command::new("git") + .args(["for-each-ref", "--format=%(refname)", "refs/"]) + .current_dir(repo_path) + .output() + .await?; + + let available_refs = String::from_utf8_lossy(&output.stdout); + tracing::error!( + "Could not detect default branch. Available refs:\n{}", + available_refs + ); + Err(WorktreeError::GitCommand( - "Could not detect default branch".to_string(), + format!("Could not detect default branch. Check if the repository at {} has any branches.", repo_path.display()), )) } |
