# A version-control benchmark for coding agents > Which version-control tool should you give your coding agent? Claude Code and Codex run the same version-control tasks three ways: with plain git, with Jujutsu, and with GitButler. Only the tool changes. The fresh six-scenario matrix passed 359 of 360 runs. GitButler passed all 120 and ran about 65% faster than git with roughly 78% fewer commands; Jujutsu had the lone miss and ran slower than git overall. Latest data: 2026-07-20. 360 graded runs (k=10 per agent-tool-scenario cell), 359 passed. ## Grader pass rate by tool, both agents combined - git: 120/120 runs passed - Jujutsu: 119/120 runs passed - GitButler: 120/120 runs passed ## Scenarios - [Selective commit](https://github.com/gitbutlerapp/version-control-bench/tree/main/tasks/pilot-1-selective-validation): A dirty working tree mixes an input-validation fix with unrelated logging, config, and debug-note edits. The task is a single commit on a new branch holding only the validation work, which spans three files, with everything else left uncommitted. - [Multi-amend](https://github.com/gitbutlerapp/version-control-bench/tree/main/tasks/pilot-2-multi-amend): A five-commit branch has uncommitted changes in the working tree that belong to three of its commits. The task routes each change into its matching commit by amending, not by adding a new one, and leaves a config tweak, a debug helper, and notes uncommitted. - [Split commit](https://github.com/gitbutlerapp/version-control-bench/tree/main/tasks/pilot-3-split-commit): A commit in the middle of the branch mixes validation, scoring, and documentation changes, plus stray debug edits, and a later commit is built on top of it. The instruction asks for that commit to be split into three ordered single-purpose commits, with the debug edits returned to the working tree as uncommitted changes and the commit above left in place. - [Reorder commits](https://github.com/gitbutlerapp/version-control-bench/tree/main/tasks/pilot-4-reorder-commits): The branch's contents are correct, but the retry and notification commits appear after commits that logically depend on them. The instruction asks for that block to be moved earlier in the history, with every commit's contents and message unchanged and nothing left uncommitted. - [Squash commits](https://github.com/gitbutlerapp/version-control-bench/tree/main/tasks/pilot-5-squash-commits): A seven-commit branch interleaves two standalone commits with two runs of incremental commits: a two-commit parser group and a three-commit retry group. The task squashes each run into one semantic commit and leaves the standalone commits untouched, ending with four. - [Update dirty branch](https://github.com/gitbutlerapp/version-control-bench/tree/main/tasks/pilot-6-update-dirty-branch): Main advanced by two commits while a feature branch accumulated two commits plus uncommitted work. The task rebuilds the feature branch on the new main tip, resolves both commit conflicts, and carries the dirty worktree through unchanged. ## Method A hidden, deterministic grader scores the final Git state, so two command sequences pass if they produce the same history. Every tool gets the same task and plain-English instruction, its name never appears in the prompt, and setup is excluded from timing. ## Data and definitions - [Benchmark repository](https://github.com/gitbutlerapp/version-control-bench) - [Full results JSON](https://github.com/gitbutlerapp/version-control-bench/blob/main/web/data/results.json) - [Task definitions](https://github.com/gitbutlerapp/version-control-bench/tree/main/tasks)