Skip to content

fix: only compare PRs targeting the same base branch#81

Merged
zkoppert merged 2 commits intomainfrom
fix/stacked-pr-false-positives
May 1, 2026
Merged

fix: only compare PRs targeting the same base branch#81
zkoppert merged 2 commits intomainfrom
fix/stacked-pr-false-positives

Conversation

@zkoppert
Copy link
Copy Markdown
Contributor

@zkoppert zkoppert commented May 1, 2026

Why

Stacked PRs (where PR b targets branch a and PR a targets main) are incorrectly flagged as conflicting because they naturally touch the same files. However, they cannot conflict at merge time since they target different branches.

Fixes #78

Impact

In large monorepos where this is being used, 8-11% of open PRs target a non-default branch. These PRs are candidates for false-positive conflict reports under the old logic. This fix eliminates that entire class of false positives.

What changed

Modified find_file_overlaps() in conflict_detector.py to index PRs by (base_branch, filename) instead of just filename. This ensures only PRs targeting the same base branch are compared for overlapping line changes.

Before vs After

Scenario Before After
PR b → branch a, PR amain (stacked) ❌ False conflict reported ✅ No conflict (different base branches)
Two PRs both → main touching same lines ✅ Conflict reported ✅ Conflict reported (unchanged)
PRs targeting different release branches ❌ Possible false conflict ✅ No conflict (different base branches)

Tradeoffs

Chosen approach: Index by (base_branch, filename) tuple in the file overlap detection.

Alternative considered: Explicit stacked-PR detection by checking if one PR's head branch equals another PR's base branch. Rejected because: (1) it's redundant after the base-branch equality guard, and (2) branch-name equality isn't a reliable model for all stacking workflows.

Testing

  • 4 new unit tests covering: different base branches, stacked PRs, same-base-branch still conflicts, and mixed scenarios
  • All 273 tests pass with 99% code coverage
  • Manual integration tests with DRY_RUN=true:
    • github/docs (74 PRs, 1 non-main target) — completed, 2 conflicts detected
    • a private UI monorepo (679 PRs, 75 stacked PRs) — completed, 461 conflicts detected after same-author filtering
    • In both repos, stacked PRs targeting non-default branches were correctly excluded from cross-base-branch comparisons and produced zero false positives
  • Deterministic verification script confirmed: PRs with different base branches are never compared, while PRs targeting the same base branch are still correctly flagged

Rollout

Low-risk change — the logic only adds a tighter filter to an existing comparison. PRs that previously conflicted correctly will continue to conflict (same base branch). The only behavioral change is eliminating false positives for cross-base-branch comparisons.

What to watch after merge: If users report missed conflicts, verify whether the involved PRs target the same base branch. The fix intentionally skips cross-base-branch comparisons.

@zkoppert zkoppert self-assigned this May 1, 2026
@github-actions github-actions Bot added the fix Bug fix label May 1, 2026
@zkoppert zkoppert marked this pull request as ready for review May 1, 2026 14:30
@zkoppert zkoppert requested a review from jmeridth as a code owner May 1, 2026 14:30
Copy link
Copy Markdown

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

This PR fixes false-positive conflict detection for stacked PRs by ensuring overlap checks only compare pull requests that target the same base branch.

Changes:

  • Update find_file_overlaps() to index by (base_branch, filename) rather than only filename.
  • Extend unit tests to cover different-base-branch and stacked-PR scenarios.
  • Loosen pylint’s max-module-lines limit to accommodate the expanded test module.
Show a summary per file
File Description
conflict_detector.py Restricts file/line overlap comparisons to PRs sharing the same base branch.
test_conflict_detector.py Adds coverage for cross-base-branch and stacked-PR cases; extends PR test helper to allow base/head branches.
.github/linters/.python-lint Increases allowed Python module length to avoid lint failures with the enlarged test file.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 2

Comment thread .github/linters/.python-lint
Comment thread test_conflict_detector.py
zkoppert and others added 2 commits May 1, 2026 11:31
Previously, the conflict detector compared all open PRs against each
other regardless of their target branch. This caused false positives
for stacked PRs where PR `b` targets branch `a` and PR `a` targets
`main` — they naturally touch the same files but cannot conflict at
merge time since they target different branches.

The fix indexes PRs by (base_branch, filename) so only PRs targeting
the same base branch are compared for overlapping line changes.

Fixes #78

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Zack Koppert <zkoppert@github.com>
Guard against potential None value in base_branch when indexing
file overlaps, ensuring consistent grouping behavior even if
PullRequestData is constructed without a base_branch value.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Zack Koppert <zkoppert@github.com>
@zkoppert zkoppert force-pushed the fix/stacked-pr-false-positives branch from 59f4a30 to 479a0e1 Compare May 1, 2026 18:32
@zkoppert zkoppert merged commit 530888e into main May 1, 2026
36 checks passed
@zkoppert zkoppert deleted the fix/stacked-pr-false-positives branch May 1, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrectly considers PRs targeting other PR branches as conflicting

3 participants