Split PR by CODEOWNERS Groups
Split a large pull request into multiple smaller PRs, where each PR touches
the fewest possible CODEOWNERS reviewer groups. The goal is to reduce review
burden: a PR that only touches megatron/core/ needs only the core reviewers,
while a PR that also touches examples/, tools/, and megatron/training/
pulls in many additional groups.
Answer-First Constraints
For split-planning questions, lead with these constraints before the full
workflow:
- Minimize CODEOWNERS reviewer groups per PR, but each resulting PR must still
be independently mergeable and reviewable.
- Tests travel with the production code they validate; do not split tests into a
separate PR just to reduce reviewer groups.
- If PR B depends on symbols renamed in PR A, call out the dependency and put
backward-compatible aliases, re-exports, or shims in PR A when needed.
- GitHub's standard stacked-PR flow
— push each branch to the upstream repo and base each PR on the previous
branch — does not work here: contributors cannot push branches to
NVIDIA/Megatron-LM, and a PR's base must be an upstream branch. The only
upstream refs containing a fork PR's commits are the pull-request/<N>
mirrors that copy-pr-bot creates, so stacking goes through them.
- Create every PR with base
main; the pull-request/<N> mirror refs do not
exist until a vetter comments /ok to test <head-sha> (copy-pr-bot). Once
the mirror exists, stack a dependent PR with
gh pr edit <child> --base pull-request/<base PR number>.
- Never merge a PR while its base is a
pull-request/* ref: the squash lands
in the bot's scratch ref, not main, and the PR ends up MERGED and
unreopenable. Retarget to main first.
- Wait for user approval before execution.
- Execution creates draft PRs from the right base, applies file-scoped diffs
with
git diff upstream/main..<source-branch> -- <paths> | git apply, pushes
to the user's fork, and never pushes directly to upstream.
Workflow
1. Analyze the PR
- Fetch the PR details:
gh pr view <number> --repo NVIDIA/Megatron-LM --json title,body,headRefName,author and gh pr diff <number> --repo NVIDIA/Megatron-LM --stat. Also determine the current GitHub user with gh api user --jq .login.
- Parse
.github/CODEOWNERS to build a mapping from file path patterns to owner groups.
- For each changed file in the PR, determine which CODEOWNERS groups would be required to review it.
- Build a summary table grouped by CODEOWNERS group, showing which files pull in which groups.
- Count the total number of distinct reviewer groups the PR currently requires.
2. Propose a split that minimizes reviewer groups per PR
The primary optimization goal: minimize the number of CODEOWNERS reviewer groups required for each resulting PR.
Strategy:
- Cluster files by their CODEOWNERS groups. Files owned by the same set of groups naturally belong together.
- Identify the largest cluster — this becomes the first (and usually largest) PR.
- Remaining files form one or more additional PRs, each ideally requiring only one or two reviewer groups.
- If a split creates a dependency (e.g., PR B uses symbols renamed in PR A), the dependent PR must be merged after the first. Note this explicitly.
- Each PR must be independently mergeable to main — no broken imports, no missing symbols. Backward-compatible aliases and re-export stubs in the first PR can make this possible.
Present the proposed split as a table:
- PR name/description
- Files included
- CODEOWNERS groups required
- Dependencies on other PRs (if any)
Wait for user approval before proceeding.
3. Execute the split (after user approval)
For each new PR:
- Create a new branch from the appropriate local base (
main, or a dependency PR's branch).
- Extract the relevant changes:
git diff upstream/main..<source-branch> -- <file paths> | git apply.
- Stage, commit with a clear message, and push to the user's fork.
- Create the PR as a draft with base
main (per repo contributing guidelines). Retarget dependent PRs to pull-request/<base PR number> only after a vetter's /ok to test has created that mirror ref.
- If the original PR needs to be narrowed in scope, confirm with the user before force-pushing.
- Report all PR URLs when done.
Important guidelines
- Always create PRs as drafts and push to the user's fork, never directly to upstream.
- Backward-compatible changes (aliases, re-exports, deprecation shims) should go in the first PR so subsequent PRs can depend on them.
- Test files should go with the production code they test, not in a separate PR.
- Prefer a single clean commit per split PR over replaying the original commit history.
- If a file is hard to categorize (e.g., it touches two groups), ask the user which PR it should go in.
- If the current GitHub user is not the author of the original PR, each new PR's description must explicitly credit the original author (e.g., "Original changes by @ in #").
1---2name: mcore-split-pr-33description: Split a PR into multiple PRs to reduce the number of required CODEOWNERS reviewer groups.4license: Apache-2.05---67# Split PR by CODEOWNERS Groups89Split a large pull request into multiple smaller PRs, where each PR touches10the fewest possible CODEOWNERS reviewer groups. The goal is to reduce review11burden: a PR that only touches `megatron/core/` needs only the core reviewers,12while a PR that also touches `examples/`, `tools/`, and `megatron/training/`13pulls in many additional groups.1415## Answer-First Constraints1617For split-planning questions, lead with these constraints before the full18workflow:1920- Minimize CODEOWNERS reviewer groups per PR, but each resulting PR must still21 be independently mergeable and reviewable.22- Tests travel with the production code they validate; do not split tests into a23 separate PR just to reduce reviewer groups.24- If PR B depends on symbols renamed in PR A, call out the dependency and put25 backward-compatible aliases, re-exports, or shims in PR A when needed.26- [GitHub's standard stacked-PR flow](https://docs.github.com/en/pull-requests/how-tos/create-pull-requests/creating-stacked-pull-requests)27 — push each branch to the upstream repo and base each PR on the previous28 branch — does not work here: contributors cannot push branches to29 `NVIDIA/Megatron-LM`, and a PR's base must be an upstream branch. The only30 upstream refs containing a fork PR's commits are the `pull-request/<N>`31 mirrors that copy-pr-bot creates, so stacking goes through them.32- Create every PR with base `main`; the `pull-request/<N>` mirror refs do not33 exist until a vetter comments `/ok to test <head-sha>` (copy-pr-bot). Once34 the mirror exists, stack a dependent PR with35 `gh pr edit <child> --base pull-request/<base PR number>`.36- Never merge a PR while its base is a `pull-request/*` ref: the squash lands37 in the bot's scratch ref, not `main`, and the PR ends up MERGED and38 unreopenable. Retarget to `main` first.39- Wait for user approval before execution.40- Execution creates draft PRs from the right base, applies file-scoped diffs41 with `git diff upstream/main..<source-branch> -- <paths> | git apply`, pushes42 to the user's fork, and never pushes directly to upstream.4344## Workflow4546### 1. Analyze the PR47481. Fetch the PR details: `gh pr view <number> --repo NVIDIA/Megatron-LM --json title,body,headRefName,author` and `gh pr diff <number> --repo NVIDIA/Megatron-LM --stat`. Also determine the current GitHub user with `gh api user --jq .login`.492. Parse `.github/CODEOWNERS` to build a mapping from file path patterns to owner groups.503. For each changed file in the PR, determine which CODEOWNERS groups would be required to review it.514. Build a summary table grouped by CODEOWNERS group, showing which files pull in which groups.525. Count the total number of distinct reviewer groups the PR currently requires.5354### 2. Propose a split that minimizes reviewer groups per PR5556The primary optimization goal: **minimize the number of CODEOWNERS reviewer groups required for each resulting PR**.5758Strategy:591. Cluster files by their CODEOWNERS groups. Files owned by the same set of groups naturally belong together.602. Identify the largest cluster — this becomes the first (and usually largest) PR.613. Remaining files form one or more additional PRs, each ideally requiring only one or two reviewer groups.624. If a split creates a dependency (e.g., PR B uses symbols renamed in PR A), the dependent PR must be merged after the first. Note this explicitly.635. Each PR must be independently mergeable to main — no broken imports, no missing symbols. Backward-compatible aliases and re-export stubs in the first PR can make this possible.6465Present the proposed split as a table:66- PR name/description67- Files included68- CODEOWNERS groups required69- Dependencies on other PRs (if any)7071Wait for user approval before proceeding.7273### 3. Execute the split (after user approval)7475For each new PR:761. Create a new branch from the appropriate local base (`main`, or a dependency PR's branch).772. Extract the relevant changes: `git diff upstream/main..<source-branch> -- <file paths> | git apply`.783. Stage, commit with a clear message, and push to the user's fork.794. Create the PR as a **draft** with base `main` (per repo contributing guidelines). Retarget dependent PRs to `pull-request/<base PR number>` only after a vetter's `/ok to test` has created that mirror ref.805. If the original PR needs to be narrowed in scope, confirm with the user before force-pushing.816. Report all PR URLs when done.8283## Important guidelines8485- Always create PRs as **drafts** and push to the user's fork, never directly to upstream.86- Backward-compatible changes (aliases, re-exports, deprecation shims) should go in the first PR so subsequent PRs can depend on them.87- Test files should go with the production code they test, not in a separate PR.88- Prefer a single clean commit per split PR over replaying the original commit history.89- If a file is hard to categorize (e.g., it touches two groups), ask the user which PR it should go in.90- If the current GitHub user is not the author of the original PR, each new PR's description must explicitly credit the original author (e.g., "Original changes by @<author> in #<number>").