@@ -442,16 +442,77 @@ async function generateGitPatch(branchName, baseBranch, options = {}) {
442442 // The measurement itself (stream to temp file via `git diff --output`, stat,
443443 // cleanup) is extracted into git_patch_utils.computeIncrementalDiffSize so
444444 // it is O(1) memory and independently unit-testable against a real repo.
445+ //
446+ // When the agent has merged the default branch into the PR branch (to resolve
447+ // conflicts or sync a stale branch), the naive diff base of `origin/<branch>`
448+ // (the PR's old head) inflates diffSize to include all of the default branch's
449+ // new commits — even though those commits are already on origin/<defaultBranch>
450+ // and represent no new content in the PR. Fix: when the merge-base between
451+ // origin/<defaultBranch> and the local branch is NOT an ancestor of the PR's
452+ // current head (baseCommitSha), the agent merged default-branch commits ahead
453+ // of the PR head. Use the merge-base as the effective diff base to exclude those
454+ // merged upstream commits from the size measurement.
455+ let diffBaseForSize = baseCommitSha ;
456+ if ( mode === "incremental" && baseCommitSha && branchName && defaultBranch ) {
457+ try {
458+ let baseBranchRemoteRef = null ;
459+ try {
460+ execGitSync ( [ "show-ref" , "--verify" , "--quiet" , `refs/remotes/origin/${ defaultBranch } ` ] , { cwd } ) ;
461+ baseBranchRemoteRef = `refs/remotes/origin/${ defaultBranch } ` ;
462+ } catch {
463+ // origin/<defaultBranch> not available locally; skip the adjustment
464+ }
465+ if ( baseBranchRemoteRef ) {
466+ // Only adjust the diff base when baseCommitSha is an ancestor of the local
467+ // branch tip. If it is NOT an ancestor the branch was rewritten (rebase /
468+ // force-push); in that case the merge-base adjustment could undercount by
469+ // ignoring commits that changed relative to the remote, so keep the original
470+ // baseCommitSha as the diff base.
471+ let baseIsAncestorOfBranch = false ;
472+ try {
473+ execGitSync ( [ "merge-base" , "--is-ancestor" , "--" , baseCommitSha , branchName ] , { cwd } ) ;
474+ baseIsAncestorOfBranch = true ;
475+ } catch {
476+ // baseCommitSha is not an ancestor of branchName (rebase / force-push)
477+ debugLog ( `Strategy 1 (incremental): baseCommitSha ${ baseCommitSha } is not an ancestor of ${ branchName } (rebase/force-push?); skipping merge-base adjustment` ) ;
478+ }
479+
480+ if ( baseIsAncestorOfBranch ) {
481+ const mb = execGitSync ( [ "merge-base" , "--" , baseBranchRemoteRef , branchName ] , { cwd } ) . trim ( ) ;
482+ // Check if mb is already an ancestor of baseCommitSha.
483+ // If it is, baseCommitSha is "later" and the agent did NOT merge the default
484+ // branch ahead of the PR head — keep baseCommitSha as the diff base.
485+ // If mb is NOT an ancestor of baseCommitSha, the agent merged default-branch
486+ // commits that are beyond the PR head. Use mb to exclude those commits from
487+ // the incremental diff size measurement.
488+ let mbIsAncestorOfBase = false ;
489+ try {
490+ execGitSync ( [ "merge-base" , "--is-ancestor" , "--" , mb , baseCommitSha ] , { cwd } ) ;
491+ mbIsAncestorOfBase = true ;
492+ } catch {
493+ // mb is not an ancestor of baseCommitSha
494+ }
495+ if ( ! mbIsAncestorOfBase ) {
496+ debugLog ( `Strategy 1 (incremental): agent merged ${ defaultBranch } ahead of PR head; using merge-base ${ mb } as diff base instead of PR head ${ baseCommitSha } ` ) ;
497+ diffBaseForSize = mb ;
498+ }
499+ }
500+ }
501+ } catch ( adjustErr ) {
502+ debugLog ( `Strategy 1 (incremental): diff-base adjustment failed (${ getErrorMessage ( adjustErr ) } ); using original base` ) ;
503+ }
504+ }
505+
445506 let diffSize = null ;
446- if ( mode === "incremental" && baseCommitSha && branchName ) {
507+ if ( mode === "incremental" && diffBaseForSize && branchName ) {
447508 diffSize = computeIncrementalDiffSize ( {
448- baseRef : baseCommitSha ,
509+ baseRef : diffBaseForSize ,
449510 headRef : branchName ,
450511 cwd,
451512 tmpPath : `${ patchPath } .diff.tmp` ,
452513 excludedFiles : options . excludedFiles ,
453514 } ) ;
454- debugLog ( `Final: diffSize=${ diffSize ?? "(n/a)" } bytes (baseRef=${ baseCommitSha } ..${ branchName } )` ) ;
515+ debugLog ( `Final: diffSize=${ diffSize ?? "(n/a)" } bytes (baseRef=${ diffBaseForSize } ..${ branchName } )` ) ;
455516 }
456517
457518 debugLog ( `Final: SUCCESS - patchSize=${ patchSize } bytes, patchLines=${ patchLines } , diffSize=${ diffSize ?? "(n/a)" } bytes, baseCommit=${ baseCommitSha || "(unknown)" } ` ) ;
0 commit comments