Skip to content

Auto-switch push_to_pull_request_branch to bundle transport when merge commits are detected#30287

Merged
pelikhan merged 3 commits intomainfrom
copilot/fix-push-to-pull-request-branch
May 5, 2026
Merged

Auto-switch push_to_pull_request_branch to bundle transport when merge commits are detected#30287
pelikhan merged 3 commits intomainfrom
copilot/fix-push-to-pull-request-branch

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 5, 2026

Long-running PR branches that merge their base branch locally produce patches git am --3way cannot apply, blocking every subsequent push (e.g. autoloop on tsessebe). The bundle transport already handles this but is opt-in.

Changes

  • safe_outputs_handlers.cjs — In pushToPullRequestBranchHandler, when patch-format is not explicitly configured and origin/<branch>..<branch> contains ≥1 merge commit, flip useBundle = true. Explicit patch-format: am is still honored. The bundle code path now also computes the incremental net diff_size via computeIncrementalDiffSize(baseCommit..branch) and records it on the safe-output entry, so the downstream push step validates max_patch_size against the actual net change rather than the on-disk bundle artifact (which on long-running branches accumulates packed git objects and per-commit metadata, and can exceed the limit even when each iteration only changes a few KB).
  • git_helpers.cjs — New hasMergeCommitsInRange(baseRef, headRef, { cwd }) wrapping git rev-list --merges --count. Best-effort: returns false on any git error so detection failures fall through to existing behavior. Uses local refs only (no extra fetch).
  • Tests — Two cases in safe_outputs_handlers.test.cjs: (a) merge-commit scenario produces a bundle, emits the auto-switch debug line, and records a non-negative diff_size on the entry; (b) explicit patch_format: am is respected even with merges in range.
  • Changeset — Patch-level entry documenting the new behavior, including the diff_size recording for bundle transport.

Detection logic

const patchFormatExplicit =
  pushConfig["patch_format"] !== undefined || config["patch_format"] !== undefined;
let useBundle = pushPatchFormat === "bundle";

if (!useBundle && !patchFormatExplicit && entry.branch) {
  if (hasMergeCommitsInRange(`refs/remotes/origin/${entry.branch}`, entry.branch, { cwd: repoCwd || undefined })) {
    useBundle = true; // git am can't apply merge commits
  }
}

Notes for review

  • Scoped to push_to_pull_request_branch (incremental). create_pull_request (full mode) is not auto-switched here — that path rarely produces merge commits since the branch is typically new, and the range computation is more involved. Can extend if needed.
  • Detection range matches what would be sent: refs/remotes/origin/<branch>..<branch> against the local checkout, identical to what the patch generator uses in incremental mode.
  • Users can still force am via explicit patch-format: am if they want the prior failure mode (e.g. to surface a configuration mistake loudly rather than silently switching transports).
  • diff_size recording for bundle transport applies whether the bundle was selected explicitly via patch-format: bundle or auto-selected by the new merge-commit detection — so existing bundle users also benefit from accurate max_patch_size validation.

Copilot AI changed the title [WIP] Fix push_to_pull_request_branch handling of merge commits Auto-switch push_to_pull_request_branch to bundle transport when merge commits are detected May 5, 2026
Copilot finished work on behalf of mrjf May 5, 2026 06:13
Copilot AI requested a review from mrjf May 5, 2026 06:13
@pelikhan pelikhan marked this pull request as ready for review May 5, 2026 06:59
Copilot AI review requested due to automatic review settings May 5, 2026 06:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Automatically switches push_to_pull_request_branch from patch transport to bundle transport when the incremental range contains merge commits, to avoid git am --3way failures on long-running PR branches.

Changes:

  • Added merge-commit detection in pushToPullRequestBranchHandler and auto-fallback to bundle unless patch_format was explicitly set.
  • Introduced hasMergeCommitsInRange() in git_helpers.cjs using git rev-list --merges --count.
  • Added tests covering auto-switch behavior and explicit patch_format: am, plus a changeset entry documenting the behavior.
Show a summary per file
File Description
actions/setup/js/safe_outputs_handlers.test.cjs Adds regression tests for merge-commit auto-switching and explicit am override behavior.
actions/setup/js/safe_outputs_handlers.cjs Implements merge-commit detection and conditional auto-switch from patch to bundle transport.
actions/setup/js/git_helpers.cjs Adds a helper to detect whether a ref range contains merge commits.
.changeset/patch-auto-bundle-on-merge-commits.md Documents the new auto-fallback behavior for release notes.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (2)

actions/setup/js/safe_outputs_handlers.cjs:591

  • Switching to bundle here bypasses the excluded_files filtering that this handler only applies on the patch path (pushPatchOptions.excludedFiles). generateGitBundle has no equivalent exclusion support, so a branch with merge commits can end up pushing files that the workflow explicitly configured to omit. The auto-switch should be disabled when excluded_files is set, or bundle generation needs matching exclusion logic first.
    if (!useBundle && !patchFormatExplicit && entry.branch) {
      const hasMerges = hasMergeCommitsInRange(`refs/remotes/origin/${entry.branch}`, entry.branch, { cwd: repoCwd || undefined });
      if (hasMerges) {
        server.debug(`push_to_pull_request_branch: detected merge commit(s) in incremental range origin/${entry.branch}..${entry.branch}; auto-switching to bundle transport (set patch-format: am to override).`);
        useBundle = true;

actions/setup/js/safe_outputs_handlers.cjs:591

  • Auto-switching to bundle here also skips the protected-file / allowed-files enforcement in the actual push step. That code inspects patchContent, but bundle pushes have no patch content, so checkFileProtection("") treats the change as touching no files (actions/setup/js/push_to_pull_request_branch.cjs:247-265 and actions/setup/js/manifest_file_helpers.cjs:202-229). As a result, any branch with a merge commit can bypass those safeguards entirely once this fallback fires.
    if (!useBundle && !patchFormatExplicit && entry.branch) {
      const hasMerges = hasMergeCommitsInRange(`refs/remotes/origin/${entry.branch}`, entry.branch, { cwd: repoCwd || undefined });
      if (hasMerges) {
        server.debug(`push_to_pull_request_branch: detected merge commit(s) in incremental range origin/${entry.branch}..${entry.branch}; auto-switching to bundle transport (set patch-format: am to override).`);
        useBundle = true;
  • Files reviewed: 4/4 changed files
  • Comments generated: 1

Comment on lines +587 to +591
if (!useBundle && !patchFormatExplicit && entry.branch) {
const hasMerges = hasMergeCommitsInRange(`refs/remotes/origin/${entry.branch}`, entry.branch, { cwd: repoCwd || undefined });
if (hasMerges) {
server.debug(`push_to_pull_request_branch: detected merge commit(s) in incremental range origin/${entry.branch}..${entry.branch}; auto-switching to bundle transport (set patch-format: am to override).`);
useBundle = true;
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented May 5, 2026

@copilot review all comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 5, 2026

@copilot review all comments

Addressed in 63532bd: the bundle code path now computes the incremental net diff_size via computeIncrementalDiffSize(baseCommit..branch) and records it on the safe-output entry, so the downstream push step validates max_patch_size against the actual change rather than the on-disk bundle artifact (which on long-running branches accumulates packed git objects). The existing patch-path behavior is unchanged. Test updated to assert diff_size is set on the auto-switched entry.

Copilot AI requested a review from pelikhan May 5, 2026 07:11
@pelikhan pelikhan merged commit e6c0bf3 into main May 5, 2026
@pelikhan pelikhan deleted the copilot/fix-push-to-pull-request-branch branch May 5, 2026 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

push_to_pull_request_branch cannot handle merge commits — blocks long-running branch workflows

4 participants