Apply to my task
arXiv:2610.11593 ★ 81 Oct 8, 2026

RucTangle: splitting an agent's giant patch into commits where the code runs after every single one

Key result

Finding: standard ways of splitting a patch into commits slice the code "by meaning" and ignore whether it runs. With baseline methods, a fifth to a third of histories contained at least one broken commit. The RucTangle method turns one huge diff from a coding agent into a chain of small commits where every version runs. The model does the grouping, the environment checks that it runs. If a version fails, the repair ladder kicks in: reorder, regroup, merge. The final code doesn't change. With a history like this, an agent fixes regressions noticeably more often: about +17% relative, versus 4–6% for competitors.

01

TL;DR

RucTangle is a method that turns one enormous diff from a coding agent into a tidy chain of small commits. Each commit serves one purpose: a feature, a refactor, or a bug fix. Here's the mechanics: the agent first proposes a plan (which edits go into which commit, and in what order), then the commits are applied one at a time. After each one, the system checks that the project still runs. If the check fails, the plan gets repaired along a ladder: reorder the commits, regroup the edits, and as a last resort merge neighboring commits.

The headline finding: existing patch-splitting methods don't think about whether the code runs. The model slices the diff "by meaning," and the intermediate versions often break. Classic example: one commit removes an old name from a dictionary, and the next commit updates the reference to it. In between, the project crashes. With the baseline methods, anywhere from a fifth to a third of histories contained at least one broken intermediate version. A history like that can't be reviewed properly, can't be rolled back piece by piece, and can't be run through git bisect.

The core of the method: plan → run check after every commit → repair the plan along the ladder, while the final code stays exactly the same. A side benefit: on a working history you can run git bisect and find the commit that broke the tests. Hand that history and the culprit commit to another agent tasked with fixing the regression, and it succeeds noticeably more often. The relative gain in successful fixes averages about 17%, versus 4–6% for competitors.

Want this for your own case? Apply this study to your task: AI adapts its method to what you are working on and writes the prompt.

02

Method Blueprint

STEP 1: Agent reads the diff → commit plan: [group of edits + message stating the purpose], in dependency order
        (if a single edit mixes purposes, the agent splits it into parts)
STEP 2: Plan check: every edit lands in exactly one commit, no empty commits
        → apply commits one by one from the base version, run check after each
STEP 3: If the check fails, climb the repair ladder:
        3a. reorder commits (a module shows up later than it's used)
        3b. fresh agent session: plan + error text → regroup/reorder (up to 2 times)
        3c. still failing → merge the failing commit with the next one until the version runs
STEP 4: The final result must match the original patch byte for byte
STEP 5 (optional): git bisect on failing tests → candidate commit → into the repair agent's context

Steps 1–3 can run in a single agent session with git and terminal access. The author of the method drove them with an orchestrator written in code.

03

Example in Practice

Task: In one evening, Claude Code rewrote payment processing in a Django store to go through Stripe. The result is one diff across 40 files: a new integration, renamed models, and, "while it was in there," a fix for a sales-tax bug. Reviewing this is impossible. If something breaks in production, you can only roll back everything at once, and you definitely don't want to roll back the sales-tax fix.

Prompt:

You are a meticulous developer preparing a large patch for review.

Context: the feature/stripe branch contains all my changes relative to main.
They're mixed together: the Stripe integration, renaming models Order → Payment,
and a fix for the sales-tax calculation.

<Task>
Split the changes into a sequence of commits where each commit
serves ONE purpose (feature / refactor / bug fix).
</Task>

<Rules>
1. First draft a plan: a list of commits, each with a message stating its purpose and a list of files/hunks.
   Every edit goes into exactly one commit. Show me the plan before executing.
2. The order respects dependencies: a module must appear before anything imports it.
3. If a single hunk mixes several purposes, split it.
4. After EACH commit, run `pytest --collect-only`. The version must run.
5. If the check fails:
   a) first try reordering the commits;
   b) if that doesn't help, regroup the edits (2 attempts max);
   c) if it still fails, merge this commit with the next one.
6. Edits that can't be separated without breaking things stay together.
7. At the end, compare the final state with the original branch (`git diff`).
   There must be no difference. If there is, fix it.
8. Do not fix correctness tests. The job is only to reorganize the history.
</Rules>

At the end, output: the list of commits, the run-check result after each,
and the result of the final comparison.

Result: first the model shows a plan of several commits with purpose messages: say, the model refactor on its own, the integration on its own, the sales-tax fix on its own. Then it makes the commits one at a time and runs test collection after each. If an import breaks somewhere, you'll watch it reorder or merge commits. At the end you get a report: the list of commits, the run status of every version, and confirmation that the final code matches the original.

04

Why It Works

The weakness: the model slices the patch "by meaning" and can't see which edits are coupled at runtime. A rename in one place and a usage in another look like two different purposes. In reality they can't be split, or you get a KeyError or ImportError between commits. Judging "by meaning" won't reveal that. You need an actual check.

The strength: the model is good at grouping edits by purpose and writing clear messages. It can also read an error message and figure out what's wrong: "the module shows up later than it's imported." That gives it a precise repair signal.

How the method exploits this: the model does the grouping, while the environment does the run check. The error stops being a hunch and becomes a fact. The repair ladder (reorder → regroup → merge) goes from the cheapest, safest move to the bluntest one. Merging always preserves a working state, even if the price is bigger commits.

Control knobs: - The check command. pytest --collect-only verifies that the project loads. For your stack, swap in a build, a linter, tsc --noEmit, go build. The stricter the check, the fewer commits you'll end up with. - Number of regrouping attempts (2 in the paper). Raise it for large patches, lower it to save tokens. - Granularity of purpose. Want big chunks? Say "5 commits max." Want finer slices? Say "every functional purpose separately." - Show the plan before executing. Keep this if you want control over the grouping. Drop it if you want full automation.

05

Prompt Template

<Role>
You are a developer preparing a large patch for review. Your goal is a history
of small commits where each serves one purpose and the project runs after every one.
</Role>

<Input>
Base version: {base_branch_or_commit}
Final version (the whole patch): {branch_with_changes}
Run-check command: {check_command}
</Input>

<Step_1_Plan>
Read the diff and the surrounding code. Draft a commit plan:
- a message describing the PURPOSE (not a list of files),
- the list of edits in each commit,
- an order that respects dependencies.
Every edit goes into exactly one commit. If an edit mixes several purposes, split it into smaller ones.
Show the plan and wait for approval: {approval_needed: yes/no}.
</Step_1_Plan>

<Step_2_Check>
Apply the commits one by one starting from the base version.
After each, run: {check_command}.
Record the result: RUNS / FAILS + error text.
</Step_2_Check>

<Step_3_Repair>
If a version fails, climb the ladder:
1. Reorder the commits (use the error text to figure out which commit must come earlier).
2. If that doesn't help, regroup/split the edits based on the error. {max_attempts} attempts max.
3. If that doesn't help, merge the failing commit with the next one. Repeat until the version runs.
After every change, re-check ALL intermediate versions.
</Step_3_Repair>

<Constraints>
- The state after the last commit must exactly match {branch_with_changes}. Verify with git diff.
- Don't change code, don't fix bugs, don't improve anything: only reorganize.
- If the final version doesn't run on its own, stop and report it.
</Constraints>

<Output>
Table: commit # | purpose | runs (yes/no) | was it merged.
Then: the result of the final comparison.
</Output>

What to fill in: {check_command} is whatever actually tells you "the project is alive" (tests, build, linter). {max_attempts} is usually 2. {approval_needed} should be "yes" for important branches.

🚀 Quick start: paste this into a chat or an agent (Claude Code, Cursor):

Here's the RucTangle template. Adapt it to my task: {describe: repository, stack, what the patch is}.
Ask me questions to fill in the fields.

[paste the template above]

The LLM will ask how to check that the project runs in your stack, which branches to compare, and whether you want to approve the plan manually. Without a check command the method doesn't work: the model has no way of knowing an intermediate version is broken.

06

Limitations

⚠️ "Runs" ≠ "works correctly": in the paper, the check is just pytest test collection. A commit can pass it and still contain a regression. The method doesn't guarantee that every intermediate commit is correct.

⚠️ The original patch has to run on its own: if the final version fails the check, you can't both preserve the final code and make every step runnable.

⚠️ The price of reliability is bigger commits: if edits can't be separated without breaking things, they get merged. Worst case, you end up with a single commit. So look not only at "does it run" but also at the number of commits.

⚠️ Misleading messages do damage: in the trajectory analysis, the repair agent sometimes second-guessed a correct fix over and over because it contradicted an inaccurate commit message. A bad description is worse than no description.

⚠️ Narrow evaluation: everything was tested on Python projects from a single benchmark and with two small open repair models. The effect is modest: single-digit percentage points in absolute terms.

⚠️ Full automation needs code: the paper implemented the method as an orchestrator. In a regular agent you can reproduce it with instructions, but with weaker guarantees.

07

How They Tested It

The idea was simple: see what happens to patches with a method that doesn't just group edits but actually runs the code after each commit. For the first test, the researchers took 131 patches from a Claude Opus 4.6 agent across 100 Python repositories (the SWE-CI benchmark). They compared RucTangle with four baseline methods. With RucTangle, every history passed the run check at every step. With the baselines, 20.6% to 37.4% of histories contained at least one broken intermediate version.

The second test was practical. The researchers collected 453 patches from six different agents, each of which broke previously passing tests. Then two other agents (running Qwen3-Coder-Next and Nemotron) were asked to fix those regressions. Three conditions were compared: no history, a history from competitors (Armchr, Atomizer), and a RucTangle history plus the git bisect result (a hint about which commit broke the tests). The first-attempt fix rate rose from 26.9% to 31.3% for Qwen and from 30.8% to 36.0% for Nemotron. The average relative gain was 16.6%, versus 4.5% and 6.1% for the competitors.

The surprise: splitting into commits helps even without bisect, but much less. That makes it unclear how much of the gain comes from the working history and how much from pointing at the "guilty" commit. Another unexpected result: a bad commit message can throw the agent off the right track. The practical takeaway: a history is useful context for an agent, but only if the messages honestly describe the purpose of the edits.

08

Adaptations and Extrapolations

🔧 Technique: add bisect context when fixing → the agent finds the source of a regression faster

When tests break after an agent's work, don't just ask it to "fix everything." First split the patch with the template above, then give a fresh session this:

Tests {failing_test_names} passed on {base_branch} but fail on {agent_branch}.
The history is split into commits. Run git bisect on these tests, find the commit
after which they fail, and fix the regression. Don't break other tests.
Commit messages are a hint about intent, but check against the diff itself, not just the message.

The last line guards against what the paper observed: the agent getting stuck on an inaccurate message.

🔧 Technique: add a rule to the agent's instructions file → splitting becomes a habit

In CLAUDE.md or AGENTS.md:

When working on a task that touches more than 5 files, commit in small steps.
One commit, one purpose (feature, refactor, or bug fix). After each commit,
run {check_command}. Never leave a version in the history that doesn't run.
The commit message describes the purpose, not a list of files.

This turns the method from a one-off patch cleanup into prevention: patches come out "clean" from the start. The paper's author did not test this adaptation directly.

09

Resources

  • Paper: Runnable Commit Untangling for Coding Agents (Jiang et al., preprint). Methods: RucTangle (splitting) and TangleEval (evaluation via regression repair).
  • Benchmark: SWE-CI, which measures how agents evolve and maintain existing code over several iterations.
  • Compared against: Armchr, Atomizer (commit-splitting methods).
  • Repositories/tools: git bisect, pytest, mini-swe-agent (the harness for the repair agents).
  • An idea from industry: the Linux kernel rule that the build must work after every patch in a series. The paper's epigraph is from Martin Fowler: "Change programs in small steps."
  • University names and the full author list were not given in the provided excerpt.

Research digest

Key result

Finding: standard ways of splitting a patch into commits slice the code "by meaning" and ignore whether it runs. With baseline methods, a fifth to a third of histories contained at least one broken commit. The RucTangle method turns one huge diff from a coding agent into a chain of small commits where every version runs. The model does the grouping, the environment checks that it runs. If a version fails, the repair ladder kicks in: reorder, regroup, merge. The final code doesn't change. With a history like this, an agent fixes regressions noticeably more often: about +17% relative, versus 4–6% for competitors.

Principle

A three-step process: plan, run check after every commit, repair the plan. 1. The agent reads the diff and writes a plan: groups of edits, a purpose message, and an order based on dependencies. 2. Commits are applied one at a time. After each, a check runs, for example `pytest --collect-only`. 3. Version failed? Climb the repair ladder: first reorder the commits, then regroup the edits (up to 2 times), and as a last resort merge the failing commit with the next one. The ladder goes from the cheapest move to the bluntest, and merging always rescues the run. It's like taking a wardrobe apart to move it. First you try pulling out a shelf, then taking off a door. If that doesn't work, you carry the whole thing. At the end, the result is compared with the original patch via `git diff`. There should be no difference.

Why it works

The model sees "rename here" and "usage there" as two separate purposes. In reality they can't be split, or you'll hit an `ImportError` or `KeyError` between commits. You can't spot that "by meaning"; you need an actual run. The model has two sides. It's good at grouping edits by purpose and writing clear messages. It's also good at reading error text: "the module shows up later than it's imported." The environment turns the hunch "it's probably fine" into the fact "it broke right here," and the model repairs the plan based on that fact. Bonus side effect: `git bisect` works on a working history. It's a search for the commit that broke the tests. Hand the culprit commit to a repair agent, and it fixes things more often. The kicker: a bad commit message is worse than none at all. In the trajectory analysis, the repair agent repeatedly second-guessed a correct fix because it clashed with an inaccurate commit description.

When to apply

Working with code → untangling a huge diff from Claude Code, Cursor, or another agent before review, especially when one patch mixes a feature, a refactor, and a bug fix. Also useful when you need a history for `git bisect` or piece-by-piece rollback. NOT a fit if the final version doesn't run on its own: you can't keep the code and have every step run at the same time. Also a weak fit for patches where everything is tightly coupled: they'll collapse into one or two commits. Important: "runs" doesn't mean "works correctly." The method checks that the project loads, not that the logic is right. Tested only on Python projects from a single benchmark.

Mini recipe

1. Find a check command. It should show the project is alive: `pytest --collect-only`, a build, a linter, `tsc --noEmit`, or `go build`. Without it the method doesn't work. The stricter the check, the fewer commits you'll get. 2. Specify two endpoints: the base branch and the branch with the patch. The agent moves from the first to the second. 3. Ask for a plan before any action: a purpose message (not a file list), the edits in each commit, and an order based on dependencies. Every edit goes into exactly one commit. 4. Allow splitting edits. If a hunk mixes several purposes, let it cut the hunk into parts. 5. Run the check after every commit. Record the result: RUNS or FAILS plus the error text. 6. Provide the repair ladder: reorder, then regroup (2 attempts max), then merge with a neighbor. After any change, re-check all intermediate versions. 7. Forbid fixing code. The only job is to rearrange the history. Bugs and improvements are off-limits. 8. Verify the result: `git diff` against the original branch must be empty. 9. Turn the knobs. For bigger chunks, write "5 commits max." For finer ones, write "each purpose separately." For an important branch, keep plan approval. For full automation, drop it. You don't have to write all this by hand. Paste the template into the agent and ask it to quiz you about your stack.

Examples

[BAD]: `Split the changes in my branch into logical commits` [GOOD]: `You are a developer preparing a large patch for review. The feature/stripe branch mixes three things: the Stripe integration, renaming models Order to Payment, and a fix for the sales-tax calculation. First show the plan: commits with a purpose message, the edits in each, and an order based on dependencies. Every edit goes into exactly one commit. After EACH commit, run pytest --collect-only. If it fails: first reorder the commits, then regroup (2 attempts max), then merge with a neighbor. Do not fix correctness tests. At the end, compare the result with the original branch via git diff; there must be no difference. Output a table: commit number, purpose, runs yes/no, was it merged.` [BAD]: `Find which commit broke the tests and fix it` [GOOD]: `Here's a history of 6 commits, and the project runs after each one. Run git bisect on the failing test test_vat_total and find the culprit commit. Give me its number and message. Then fix the regression based on that commit.`

In plain words

Coding agents love to dump a 40-file diff in your lap, with a new feature, a refactor, and a random bug fix all tossed into one pile. Pointing a regular model at it and asking it to untangle the mess into neat pieces "by meaning" won't cut it. The model doesn't get runtime dependencies: it renames a function in one commit and calls it in another, leaving your repo with a flat-out ImportError right in the middle of your git history.

Picture movers who threw grandma's crystal, a set of dumbbells, and your muddy boots into one giant box. Technically, the move is done, but good luck pulling out a boot without smashing the glassware. You want to roll back a botched payments update in production, and the sales-tax fix you actually need gets ripped out with it, because the model tied their code into an unbreakable Gordian knot.

The cure for this nonsense is a method called RucTangle. The mechanics are simple: the agent sketches a rough plan of edits, applies them strictly one at a time, and runs the project every single time. Something broke? The repair ladder kicks in: first the agent just tries swapping commits around, then it reshuffles specific lines, and if it's truly stuck it merges neighboring edits. The one hard rule: every intermediate step has to be runnable, meaning it actually builds and works.

It was tested on coding agents, but this pattern is a lifesaver anywhere you generate software with tools like Claude Code or Cursor. Instead of wrestling with the terminal by hand, you end up with a chain of clean commits. Every change is isolated: the feature on its own, the refactor on its own. If a third-party service falls over tomorrow, you calmly roll back the problem piece instead of a whole week of work.

Bottom line: giant blind walls of code from AI models are a sure path to a heart attack during review. Stop merging everything in one lump and make your agents check that the code runs after every little sneeze. RucTangle turns a code dump into a disciplined pipeline you're not scared to ship to production. Whoever adopts this first saves a ton of stress; everyone else keeps rolling the dice with their diffs.

AI lab assistant

Apply this study to your task

Describe what you're working on. AI takes the method and the measured results from this paper and adapts them to your case, or writes a ready prompt built on them.

Based on RucTangle: splitting an agent's giant patch into commits where the code runs after every single one arXiv:2610.11593

Sign in to apply this study New accounts get 50 free credits.