summaryrefslogtreecommitdiff
path: root/makima/src/daemon/worktree
diff options
context:
space:
mode:
Diffstat (limited to 'makima/src/daemon/worktree')
-rw-r--r--makima/src/daemon/worktree/manager.rs61
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()),
))
}