Skip to content

push_to_pull_request_branch does not support multi-repo (side-repo) checkout pattern #27757

@yskopets

Description

@yskopets

Summary

push_to_pull_request_branch fails in multi-repo workflows where a target repository is checked out into a subdirectory alongside the workflow repository (e.g. via actions/checkout with a path: parameter).

Error messages observed

Two errors are returned by the tool across successive retries:

First attempt — the handler runs getCurrentBranch() without cwd, so it detects the wrong branch (from the workflow repo root). It generates a patch against that wrong branch. When the target branch has no new commits relative to that wrong baseline, the tool reports:

No new commits to push - your changes may already be on the remote branch

Second attempt — after the agent specifies the branch name explicitly, the handler tries to generate an incremental patch for the correct target branch. But git is still running in the workflow repo root, where the target branch does not exist:

Branch repo-assist/fix-issue-NNNN-<description> does not exist locally. Cannot generate incremental patch.

The agent's own conclusion from the run (via thinking):

The tool seems to be looking in the workflow repo, not in the target-repo/ subdirectory. The target-repo was checked out into target-repo/. My commits are in /home/runner/work/<workflow-repo>/<workflow-repo>/target-repo/ which is a different git repo. The safeoutputs tool may be looking at the workflow repo instead.

Root cause

The push_to_pull_request_branch handler in safe_outputs_handlers.cjs does not look up the target repo's local checkout path. All git operations (git ls-remote, git fetch, git checkout, git am, etc.) run against process.cwd(), which in a multi-repo workflow is the workflow repo root — not the subdirectory where the target repo is checked out.

Contrast with create_pull_request

The create_pull_request handler already handles this correctly:

// safe_outputs_handlers.cjs — create_pull_request handler
let repoCwd = null;
if (entry.repo && entry.repo.trim()) {
  repoSlug = repoResult.repo;
  const checkoutResult = findRepoCheckout(repoSlug);
  if (checkoutResult.success) {
    repoCwd = checkoutResult.path;
  }
}
const detectedBranch = getCurrentBranch(repoCwd);
// ...
transportOptions.cwd = repoCwd;

The push_to_pull_request_branch handler has none of this logic.

Expected behaviour

push_to_pull_request_branch should call findRepoCheckout(repoSlug) when entry.repo is set, and pass the resulting path as cwd to getCurrentBranch() and pushTransportOptions — the same pattern used by create_pull_request.

Suggested fix

In the push_to_pull_request_branch handler, after const { repoParts } = repoResult;:

let repoCwd = null;
if (entry.repo && entry.repo.trim()) {
  const repoSlug = repoResult.repo;
  const checkoutResult = findRepoCheckout(repoSlug);
  if (checkoutResult.success) {
    repoCwd = checkoutResult.path;
    entry.repo_cwd = repoCwd;
  }
}

Then:

// change
const detectedBranch = getCurrentBranch();
// to
const detectedBranch = getCurrentBranch(repoCwd);

And after const pushTransportOptions = { mode: "incremental" };:

if (repoCwd) { pushTransportOptions.cwd = repoCwd; }

Filed by Claude Code

Metadata

Metadata

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions