fix: replace git branch -a regex with rev-parse in MergeBaseValidator - #451
Conversation
✅ Deploy Preview for commit-check ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Warning Review limit reached
Next review available in: 34 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe ChangesTarget branch resolution refactor
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant Validator as MergeBaseValidator
participant Git as subprocess (git rev-parse --verify)
Caller->>Validator: _find_target_branch(pattern)
Validator->>Validator: strip ^/$ anchors
alt branch_name empty
Validator-->>Caller: None
else branch_name present
Validator->>Git: rev-parse --verify branch_name
alt local verify succeeds
Git-->>Validator: success
Validator-->>Caller: branch_name
else local verify fails
Validator->>Git: rev-parse --verify origin/branch_name
alt remote verify succeeds
Git-->>Validator: success
Validator-->>Caller: branch_name
else remote verify fails
Git-->>Validator: failure
Validator-->>Caller: None
end
end
end
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #451 +/- ##
==========================================
+ Coverage 96.60% 96.89% +0.28%
==========================================
Files 10 10
Lines 1090 1094 +4
==========================================
+ Hits 1053 1060 +7
+ Misses 37 34 -3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🧹 Nitpick comments (2)
commit_check/engine.py (2)
463-484: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDeduplicate ref verification and broaden exception handling.
The local and remote checks are identical except for the ref string, and both only catch
subprocess.CalledProcessError, so a missinggitexecutable (FileNotFoundError/OSError) would propagate unhandled instead of falling through toreturn Nonelike the rest of this method does.♻️ Proposed refactor to consolidate the duplicated verification logic
- # Try local branch first - try: - subprocess.run( - ["git", "rev-parse", "--verify", branch_name], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=True, - ) - return branch_name - except subprocess.CalledProcessError: - pass - - # Try remote tracking branch under origin/ - try: - subprocess.run( - ["git", "rev-parse", "--verify", f"origin/{branch_name}"], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=True, - ) - return branch_name - except subprocess.CalledProcessError: - pass - - return None + def _ref_exists(ref: str) -> bool: + try: + subprocess.run( + ["git", "rev-parse", "--verify", ref], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=True, + ) + return True + except (subprocess.CalledProcessError, OSError): + return False + + if _ref_exists(branch_name) or _ref_exists(f"origin/{branch_name}"): + return branch_name + + return None🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@commit_check/engine.py` around lines 463 - 484, The ref verification in the branch lookup method is duplicated and only handles subprocess.CalledProcessError, so missing git or other OS-level failures can escape instead of falling through cleanly. Refactor the local and origin/ checks in the branch-resolution logic to share a single verification path keyed by the ref string, and broaden the exception handling around subprocess.run in this method to also catch FileNotFoundError/OSError so it still returns None on any verification failure.
455-456: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMove
subprocess/reimports to module top-level.Local
import subprocess/import reinside the method is non-idiomatic; both are cheap, stdlib, and unconditionally needed, so hoist them to the top of the file for consistency with the rest of the module.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@commit_check/engine.py` around lines 455 - 456, Move the local subprocess and re imports out of the method and into the module-level import block in engine.py; these stdlib imports are used unconditionally, so update the top-of-file imports and remove the in-method import statements from the code path around the affected function.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@commit_check/engine.py`:
- Around line 463-484: The ref verification in the branch lookup method is
duplicated and only handles subprocess.CalledProcessError, so missing git or
other OS-level failures can escape instead of falling through cleanly. Refactor
the local and origin/ checks in the branch-resolution logic to share a single
verification path keyed by the ref string, and broaden the exception handling
around subprocess.run in this method to also catch FileNotFoundError/OSError so
it still returns None on any verification failure.
- Around line 455-456: Move the local subprocess and re imports out of the
method and into the module-level import block in engine.py; these stdlib imports
are used unconditionally, so update the top-of-file imports and remove the
in-method import statements from the code path around the affected function.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 29e5e2c2-0bbd-47b2-8b8c-439c762ea853
📒 Files selected for processing (2)
commit_check/engine.pytests/engine_test.py
Merging this PR will not alter performance
Comparing Footnotes
|
4735bee to
1b08d21
Compare
1b08d21 to
a13dc66
Compare
The old _find_target_branch method scanned all branches via git branch -a and used a loose regex match, which could cause false positives: a pattern like 'main' could match 'main-old', 'main-staging', etc. depending on the order git branch -a outputs branches. The new approach: 1. Strips common regex anchors (^, $) from the pattern to get a clean name 2. Uses git rev-parse --verify <name> for exact local ref resolution 3. Falls back to git rev-parse --verify origin/<name> for remote tracking This makes require_rebase_target safe to recommend to users.
a13dc66 to
be6a2c3
Compare
|

Problem
MergeBaseValidator._find_target_branchusedgit branch -a+re.match()to locate the target branch. This approach is fragile because a loose regex likemaincould matchmain-old,main-staging,origin/main, etc. — whichever appeared first ingit branch -aoutput (which is non-deterministic). This class of bug makesmerge_basevalidation unreliable in CI.Solution
Replace the regex-based branch list scan with precise ref resolution using
git rev-parse --verify:^,$) from the pattern to get a clean branch namegit rev-parse --verify refs/heads/<branch>(local branch, no ambiguity with tags)git rev-parse --verify refs/remotes/origin/<branch>(remote tracking branch)Using the full
refs/heads/andrefs/remotes/origin/paths eliminates any possibility of resolving to a tag or other non-branch ref — matching the old behavior which only scannedgit branch -a(branches only).Regression Analysis
All edge cases verified against old behavior:
regex = "^main$", branchmainexistsmainrev-parse refs/heads/main→ foundregex = "main", branches:main,main-oldmain-oldfirst (non-deterministic)refs/heads/mainmatchesregex = "develop", only remoteorigin/developremotes/origin/developrev-parse refs/remotes/origin/develop→ foundNoneNonemainexists, no branchmaingit branch -a→ not found →Nonerefs/heads/main→ not found →Nonerefs/heads/)^(main|develop)$origin(e.g.upstream)origin/Test Plan
^main$→ resolves tomainviarefs/heads/main)develop→ resolved viarefs/remotes/origin/develop)None)Nonewithout calling subprocess)