diff options
| author | soryu <soryu@soryu.co> | 2026-01-15 03:26:28 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-01-15 03:26:28 +0000 |
| commit | eeafe072bc6bb81459f7d087b48fc921afe9cc11 (patch) | |
| tree | 7f835993edd732f8ff66d756391dedffe3d44e90 /makima/src/daemon/worktree | |
| parent | c61a2b9b9c988f5460f85980d4ddf285f1a730b5 (diff) | |
| download | soryu-eeafe072bc6bb81459f7d087b48fc921afe9cc11.tar.gz soryu-eeafe072bc6bb81459f7d087b48fc921afe9cc11.zip | |
Automatically derive repo URL and add notifications for input
Diffstat (limited to 'makima/src/daemon/worktree')
| -rw-r--r-- | makima/src/daemon/worktree/manager.rs | 183 |
1 files changed, 134 insertions, 49 deletions
diff --git a/makima/src/daemon/worktree/manager.rs b/makima/src/daemon/worktree/manager.rs index 9af5dcb..ff0e9e7 100644 --- a/makima/src/daemon/worktree/manager.rs +++ b/makima/src/daemon/worktree/manager.rs @@ -333,34 +333,76 @@ impl WorktreeManager { // Create base directory tokio::fs::create_dir_all(&self.base_dir).await?; - tracing::info!( - task_id = %task_id, - worktree_path = %worktree_path.display(), - branch = %branch_name, - base_branch = %base_branch, - "Creating worktree from local branch" - ); + // Prune stale worktree entries first (handles "missing but registered" errors) + let _ = Command::new("git") + .args(["worktree", "prune"]) + .current_dir(source_repo) + .output() + .await; - // Create the worktree with a new branch based on the local base_branch - let output = Command::new("git") - .args([ - "worktree", - "add", - "-b", - &branch_name, - ]) - .arg(&worktree_path) - .arg(base_branch) + // Check if the branch already exists (e.g., from a previous run of the same task) + let branch_exists = Command::new("git") + .args(["rev-parse", "--verify", &format!("refs/heads/{}", branch_name)]) .current_dir(source_repo) .output() - .await?; + .await + .map(|o| o.status.success()) + .unwrap_or(false); - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - return Err(WorktreeError::GitCommand(format!( - "Failed to create worktree: {}", - stderr - ))); + if branch_exists { + tracing::info!( + task_id = %task_id, + worktree_path = %worktree_path.display(), + branch = %branch_name, + "Branch already exists, creating worktree from existing branch" + ); + + // Use existing branch - try without force first, then with force + let output = Command::new("git") + .args(["worktree", "add", "-f"]) + .arg(&worktree_path) + .arg(&branch_name) + .current_dir(source_repo) + .output() + .await?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(WorktreeError::GitCommand(format!( + "Failed to create worktree from existing branch: {}", + stderr + ))); + } + } else { + tracing::info!( + task_id = %task_id, + worktree_path = %worktree_path.display(), + branch = %branch_name, + base_branch = %base_branch, + "Creating worktree with new branch" + ); + + // Create the worktree with a new branch based on the local base_branch + let output = Command::new("git") + .args([ + "worktree", + "add", + "-b", + &branch_name, + ]) + .arg(&worktree_path) + .arg(base_branch) + .current_dir(source_repo) + .output() + .await?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(WorktreeError::GitCommand(format!( + "Failed to create worktree: {}", + stderr + ))); + } } tracing::info!( @@ -439,35 +481,78 @@ impl WorktreeManager { // Create base directory tokio::fs::create_dir_all(&self.base_dir).await?; - tracing::info!( - task_id = %task_id, - source_worktree = %source_worktree.display(), - worktree_path = %worktree_path.display(), - branch = %branch_name, - source_commit = %source_commit, - "Creating worktree from source task" - ); + // Prune stale worktree entries first (handles "missing but registered" errors) + let _ = Command::new("git") + .args(["worktree", "prune"]) + .current_dir(&source_repo) + .output() + .await; - // Create a new worktree based on the source commit - let output = Command::new("git") - .args([ - "worktree", - "add", - "-b", - &branch_name, - ]) - .arg(&worktree_path) - .arg(&source_commit) + // Check if the branch already exists (e.g., from a previous run of the same task) + let branch_exists = Command::new("git") + .args(["rev-parse", "--verify", &format!("refs/heads/{}", branch_name)]) .current_dir(&source_repo) .output() - .await?; + .await + .map(|o| o.status.success()) + .unwrap_or(false); - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - return Err(WorktreeError::GitCommand(format!( - "Failed to create worktree: {}", - stderr - ))); + if branch_exists { + tracing::info!( + task_id = %task_id, + source_worktree = %source_worktree.display(), + worktree_path = %worktree_path.display(), + branch = %branch_name, + "Branch already exists, creating worktree from existing branch" + ); + + // Use existing branch with force flag + let output = Command::new("git") + .args(["worktree", "add", "-f"]) + .arg(&worktree_path) + .arg(&branch_name) + .current_dir(&source_repo) + .output() + .await?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(WorktreeError::GitCommand(format!( + "Failed to create worktree from existing branch: {}", + stderr + ))); + } + } else { + tracing::info!( + task_id = %task_id, + source_worktree = %source_worktree.display(), + worktree_path = %worktree_path.display(), + branch = %branch_name, + source_commit = %source_commit, + "Creating worktree from source task with new branch" + ); + + // Create a new worktree based on the source commit + let output = Command::new("git") + .args([ + "worktree", + "add", + "-b", + &branch_name, + ]) + .arg(&worktree_path) + .arg(&source_commit) + .current_dir(&source_repo) + .output() + .await?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(WorktreeError::GitCommand(format!( + "Failed to create worktree: {}", + stderr + ))); + } } // Now copy uncommitted changes from source worktree |
