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