Skip to content

vitali87/pr-split

Repository files navigation

pr-split logo

pr-split

Decompose large PRs into a DAG of small, reviewable PRs

License gitcgr

Why pr-split?

Vibe coding with AI assistants can produce massive PRs that no one wants to review. A 2,000 line PR with changes across dozens of files is a review bottleneck: teammates skim it, rubber stamp it, or just ignore it. pr-split turns that monolith into a set of focused, bite-sized PRs your team can actually review with confidence. Each sub-PR has a clear purpose, minimal scope, and explicit dependencies, so reviewers know exactly what changed and why.

How it works

pr-split takes a large pull request (local branch, fork PR number, or user:branch), sends the diff to an LLM for analysis, and produces a split plan: a set of smaller, focused PRs arranged in a dependency DAG. Each sub-PR gets its own branch, commit, and GitHub PR targeting the correct base.

pr-split system design

Installation

# With uv (recommended)
uv tool install pr-split

# With pip
pip install pr-split

Prerequisites

  • Python 3.12+
  • GitHub CLI (gh) authenticated via gh auth login
  • ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable set when using the llm partition backend

Usage

Split a local branch

pr-split split feature-branch --base main

Split a fork PR by number

pr-split split '#42' --base main

Split a fork PR by user:branch

pr-split split someuser:feature-branch --base main

Preview a split plan without creating PRs

pr-split split feature-branch --base main --dry-run

Options

Flag Default Description
--base main Base branch for the diff
--min-loc unset Optional minimum diff lines per sub-PR
--max-loc 400 Maximum target diff lines per sub-PR
--strict-loc-bounds false Exit instead of proceeding when the final plan violates configured LOC bounds
--priority orthogonal Grouping priority (orthogonal or logical)
--chunk-strategy dynamic_programming Large-diff chunking strategy (dynamic_programming or greedy)
--partition-strategy llm Hunk-to-PR partition backend (llm, graph, or cp_sat)
--dry-run false Preview plan and save to .pr-split/plan.json without creating branches or PRs

Check status of an existing split

pr-split status

Shows a table with each sub-PR's ID, title, branch, PR number, live state (OPEN/CLOSED/MERGED), and review decision (Approved, Changes Requested, etc.) queried directly from GitHub.

Merge split PRs in dependency order

pr-split merge

Walks the dependency DAG and merges each PR in topological order. Skips already-merged, closed, draft, review-required, or changes-requested PRs. Stops if a merge fails or a dependency wasn't merged to prevent out-of-order merges.

Use --auto to queue merges behind CI checks (uses gh pr merge --auto):

pr-split merge --auto

Use --notify to POST merge results to a webhook URL (e.g. Slack, Discord):

pr-split merge --notify https://hooks.slack.com/...

Execute a saved dry-run plan

pr-split execute

Creates branches and PRs from a previously saved --dry-run plan. Uses the saved diff and merge base for consistency — safe even if the dev branch has changed since the dry run.

Interactive plan editing

After the plan is displayed, an interactive editor lets you adjust the plan before confirming:

edit> show pr-1          # inspect a group's assignments
edit> move src/foo.py:2 pr-1 pr-2   # move a hunk between groups
edit> plan               # redisplay the plan table
edit> done               # proceed (default — just press Enter)
edit> abort              # cancel

The plan is re-validated after editing to catch empty groups or coverage gaps.

Custom PR body templates

Create .pr-split/template.md to customize the body of each generated PR using placeholders:

{description}

### Files
{files}

**Stats:** +{added}/-{removed} ({loc} lines)

{dag}

Available placeholders: {description}, {files}, {added}, {removed}, {loc}, {dependencies}, {dag}, {id}, {title}.

Re-split with different parameters

Running split again when a plan already exists will prompt you to clean up existing branches and PRs before re-planning. Dry-run plans are silently overwritten.

Clean up

pr-split clean

Closes all split PRs, deletes their branches (local and remote), and removes the plan file.

Configuration

Settings can be set via environment variables with the PR_SPLIT_ prefix:

Variable Default Description
PR_SPLIT_PROVIDER anthropic LLM provider (anthropic or openai)
ANTHROPIC_API_KEY (required for Anthropic) Anthropic API key
OPENAI_API_KEY (required for OpenAI) OpenAI API key
PR_SPLIT_MODEL auto per provider Model name (defaults to best available model for the chosen provider)
PR_SPLIT_MIN_LOC unset Optional minimum target diff lines
PR_SPLIT_MAX_LOC 400 Default maximum target diff lines
PR_SPLIT_STRICT_LOC_BOUNDS false Fail if the final plan violates configured LOC bounds
PR_SPLIT_PRIORITY orthogonal Default grouping priority
PR_SPLIT_CHUNK_STRATEGY dynamic_programming Large-diff chunking strategy
PR_SPLIT_PARTITION_STRATEGY llm Hunk-to-PR partition backend
PR_SPLIT_WEBHOOK_URL (none) Webhook URL for merge notifications

Planning backends

pr-split now separates two optimization layers:

  • Chunking: for diffs that exceed the model context window, dynamic_programming chooses chunk boundaries to avoid splitting the same file when possible. greedy keeps the previous first-fit behavior.
  • Partitioning: llm preserves the original semantic planner, graph uses deterministic affinity-based grouping, and cp_sat uses an optimization model to balance group count, LOC, and cohesion.

The cp_sat backend requires the optional ortools package to be installed in the runtime environment.

For a deeper explanation of the planning model, optimization methods, scoring, and research directions, see METHODOLOGY.md.

What it does

  1. Extracts the merge-base diff between your branch and the base (same view as GitHub's PR page)
  2. Sends the diff to the configured backend (LLM, graph, or CP-SAT), which groups hunks into logical sub-PRs with dependency ordering
  3. Validates the plan: full coverage (every hunk assigned exactly once), no cycles, no merge conflicts between independent groups
  4. Shows you the plan (table + dependency tree) with an optional interactive editor to move hunks between groups
  5. Creates branches, commits, pushes, and opens GitHub PRs — materialization and push/PR creation run in parallel using git worktrees. Use --dry-run to save the plan for later execution with execute
  6. For diffs exceeding the model's context window, uses the configured chunking strategy and processes chunks sequentially while carrying forward the group catalog across chunks
  7. status, merge, and clean commands are available to track progress, merge PRs in dependency order, or clean up branches and PRs

License

MIT

About

Decompose large PRs into a DAG of small, reviewable PRs

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages