From c5769e9b6aa58afe7b958f9d49bd62c77556dadc Mon Sep 17 00:00:00 2001 From: jcfs Date: Mon, 12 Jan 2026 15:34:06 +0000 Subject: [PATCH] fix: mount git worktree metadata directory into container Git worktrees store their metadata in the parent repository's .git/worktrees/{name} directory. The worktree's .git file contains an absolute path to this directory. When mounting a worktree into a container, git commands fail because the .git file references a host path that doesn't exist in the container. This fix mounts the git worktree metadata directory into the container at the same path it exists on the host, so git commands work correctly. --- .../internal/agent/lifecycle/manager.go | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/backend/internal/agent/lifecycle/manager.go b/apps/backend/internal/agent/lifecycle/manager.go index d2b4e11b1e..571874bcf3 100644 --- a/apps/backend/internal/agent/lifecycle/manager.go +++ b/apps/backend/internal/agent/lifecycle/manager.go @@ -302,6 +302,7 @@ func (m *Manager) Launch(ctx context.Context, req *LaunchRequest) (*AgentInstanc // 3. Handle worktree creation/reuse if enabled workspacePath := req.WorkspacePath + var gitWorktreeMetadataPath string // Path to git worktree metadata for container mount if req.UseWorktree && m.worktreeMgr != nil && req.RepositoryPath != "" { wt, err := m.getOrCreateWorktree(ctx, req) if err != nil { @@ -311,9 +312,13 @@ func (m *Manager) Launch(ctx context.Context, req *LaunchRequest) (*AgentInstanc // Fall back to direct mount if worktree creation fails } else { workspacePath = wt.Path + // Git worktrees store metadata in the main repo's .git/worktrees/{name} directory + // We need to mount this into the container at the same path for git commands to work + gitWorktreeMetadataPath = filepath.Join(req.RepositoryPath, ".git", "worktrees", req.TaskID) m.logger.Info("using worktree for agent", zap.String("task_id", req.TaskID), zap.String("worktree_path", workspacePath), + zap.String("git_metadata_path", gitWorktreeMetadataPath), zap.String("branch", wt.Branch)) } } @@ -324,7 +329,7 @@ func (m *Manager) Launch(ctx context.Context, req *LaunchRequest) (*AgentInstanc // 5. Build container config from registry config (use worktree path if available) reqWithWorktree := *req reqWithWorktree.WorkspacePath = workspacePath - containerConfig := m.buildContainerConfig(instanceID, &reqWithWorktree, agentConfig) + containerConfig := m.buildContainerConfig(instanceID, &reqWithWorktree, agentConfig, gitWorktreeMetadataPath) // 6. Create and start the container containerID, err := m.docker.CreateContainer(ctx, containerConfig) @@ -1020,7 +1025,9 @@ func (m *Manager) updateInstanceError(instanceID, errorMsg string) { } // buildContainerConfig builds a Docker container config from agent registry config -func (m *Manager) buildContainerConfig(instanceID string, req *LaunchRequest, agentConfig *registry.AgentTypeConfig) docker.ContainerConfig { +// gitWorktreeMetadataPath is the host path to the git worktree metadata (e.g., /path/to/repo/.git/worktrees/{task_id}) +// If non-empty, it will be mounted into the container at the same path so git commands work correctly +func (m *Manager) buildContainerConfig(instanceID string, req *LaunchRequest, agentConfig *registry.AgentTypeConfig, gitWorktreeMetadataPath string) docker.ContainerConfig { // Build image name with tag imageName := agentConfig.Image if agentConfig.Tag != "" { @@ -1044,6 +1051,19 @@ func (m *Manager) buildContainerConfig(instanceID string, req *LaunchRequest, ag }) } + // Add git worktree metadata mount if using a worktree + // Git worktrees reference the parent repo's .git/worktrees/{name} directory via the .git file + // We need to mount this directory into the container at the same host path for git to work + if gitWorktreeMetadataPath != "" { + mounts = append(mounts, docker.MountConfig{ + Source: gitWorktreeMetadataPath, + Target: gitWorktreeMetadataPath, // Same path inside container + ReadOnly: false, + }) + m.logger.Debug("added git worktree metadata mount", + zap.String("path", gitWorktreeMetadataPath)) + } + // Merge environment variables env := make([]string, 0) // Add default env from agent config