[KongchangAI]
· 3 min read· 1,574 words

Split a Coding Agent's Giant Commit With git history split

Split a Coding Agent's Giant Commit With git history split

Git 2.54's git history split makes breaking up an AI agent's giant commit as easy as git add -p.

AI coding agents often cram multiple unrelated changes into one commit, and previously only interactive rebase could break them apart. Git 2.54 introduces the experimental `git history split`, which uses the same keystrokes as `git add -p` to pick hunks, writes the selected content into a new parent commit, and auto-migrates local branches derived from the old commit. Companion commands `reword` (2.54), `fixup` (2.55), and `drop` (2.56) cover message rewrites, folding into earlier commits, and deleting commits while replaying descendants. Back up with a tag rather than a branch, since branches get migrated too. The command doesn't handle merge commits, rejects operations ending in conflicts, doesn't run githooks, and remains experimental as of 2.56.

AI coding agents dumping a five-file, two-purpose Update checkout commit is a scene many people have run into recently. The formatting bug fix you want to merge this afternoon and the refactor you want to argue about first are crammed into the same commit. Git 2.54's experimental git history split command exists for exactly this situation: it lets you pick hunks just like git add -p, writes the selected content into a new parent commit, and automatically migrates all local branches built on top of the old commit onto the rewritten history. No to-do list, no rebase that stalls halfway through.

rss source: Split a Coding Agent's Giant Commit With git history split (Git 2.54+)

The Problem: One Commit, Two Intentions

Agents fall into this trap easily. The task says "clean up checkout," and everything it runs into along the way lands in the same commit. git show --stat HEAD~1 tells you what's wrong: five files, one message, two unrelated changes.

Two of those files fix a formatting bug users can see today and add a regression test; the other three move a hardcoded tax rate behind an interface and rewrite the related tests. That commit gives you only two buttons: take it all, or take none of it.

Before git history split, breaking it apart meant interactive rebase: mark edit, reset, re-stage hunk by hunk, commit twice, continue. Git 2.54 compresses that workflow into a single command.

Hunk is the basic unit of git diff output: Git groups each file's consecutive changes into a block with a few lines of context, forming a patch block you can accept or reject directly. Both git add -p and git history split ask questions at hunk granularity, not file or line granularity.

Note that hunk boundaries are decided by Git's diff heuristics and don't always align with semantic boundaries. A formatting fix and a logic refactor appearing adjacent in the same code region can get merged into the same hunk—this is exactly why the article mentions pressing s to split it into smaller hunks.

Splitting a Commit With git history split

Point split at that giant commit. When it sits one level below the tip, this is precisely the scenario that used to require rebase:

git history split HEAD~1

Git walks the commit's hunks in path order, asking one by one with the same keystrokes as git add -p. Answer y to move a hunk into the new commit, n to leave it in place, d to leave it and the rest of that file's hunks where they are.

After the selection is done, the editor opens twice. Both times it starts from the agent's original message: the first for the split-out commit (the new parent), the second for the portion the original commit keeps. Author information stays the same as the original commit's author.

When the changes of interest are in different files, a pathspec lets you go straight to the target without pressing d:

git history split HEAD~1 -- src/Money.php tests/MoneyTest.php

Only matching files are offered; the rest stay in the original commit.

Here's an easily overlooked judgment call: don't split out the Checkout test rewrite. The old test calls a no-argument constructor, which fails the instant the constructor needs TaxRate. Putting the refactor and the old test in the same commit turns the test suite red. The rewritten test must follow the change that forced it to change. Group hunks by "what a reviewer would approve together."

After splitting, verify nothing was lost:

git log --oneline main..agent/checkout
git diff before-split agent/checkout

The log shows three commits replacing the original two, and the diff should output nothing. According to the official docs, the original commit "keeps intact, only its parent becomes the newly split-out commit," so the code at the tip is unchanged.

On your first run against a real branch, add --dry-run. Git writes the new objects but moves no refs, and prints the ref updates for git update-ref to read. If you only want to move the current branch, pass --update-refs=head.

Use a tag, not a branch, for backup

Tag the starting point before rewriting:

git tag before-split

The choice here matters. By default git history moves all local branches derived from the rewritten commit, so a backup branch at the tip gets moved along with it. The docs only talk about moving branches, so a tag stays where you put it.

--dry-run and --update-refs are two key parameters for reducing risk. --dry-run performs all object writes and ref computation but moves no refs, only printing the git update-ref commands it would execute, so you can review before actually running them.

--update-refs=head narrows the automatic migration scope to just the single branch you're currently on. The default behavior moves all local branches derived from the rewritten commit, which can exceed expectations when you have multiple parallel working branches, so explicitly specifying this parameter is safer when you only want to rewrite the line in front of you.

Reword and fixup without rebase

The more fixes commit at the top is still there. git history reword opens any commit's message in the editor and rewrites it in place. It doesn't touch the working tree or index, and works even in a bare repository. Changing more fixes to Document the TaxRate dependency in README takes one command:

git history reword HEAD

For HEAD itself, git commit --amend does the same thing. The value of reword is for positions three or four commits back, out of amend's reach.

Then review finds a gap: the fix is missing a test for amounts below 1.00. Git 2.55's new git history fixup folds staged changes into an earlier commit and replays the commits after it on top:

git add tests/MoneyTest.php
git history fixup 'agent/checkout^{/Fix zero}'

The ^{/Fix zero} suffix finds the most recent commit on the branch whose message matches. The fixup commit keeps its original message and author; to edit the message, add --reedit-message. Git 2.56 added git history drop to delete a commit and replay its descendants onto its parent.

If agent/checkout has already been pushed, these operations rewrite history just like any rebase: push with git push --force-with-lease. To abandon the whole exercise, run git reset --hard before-split on the branch.

What It Explicitly Refuses to Do

The official man page lists the limitations directly, and most are deliberate design choices:

  • It won't touch history containing merge commits. Use git rebase --rebase-merges for those cases.
  • Any operation that would end in a merge conflict is rejected. History rewriting shouldn't leave you in a half-finished state, so it aborts outright instead of stopping partway.
  • Githooks don't run "at the current point in time". If a commit-msg hook checks message format, it won't see the messages you type during the split.
  • The hunk selector is invoked with editing disabled, so no e is offered. When a fix and a refactor share the same hunk, try s to split it into smaller hunks, or fall back to git rebase -i.

Selecting all or none is also invalid, since one of the two commits would be empty. As of 2.56 the whole command is still marked experimental, with an official warning that behavior may change.

When you need to reorder a range of commits or move them onto a new base as a whole, git rebase remains the right tool. git history covers "one targeted edit at a time."

Githooks are scripts Git calls automatically on specific events (such as pre-commit, commit-msg, post-commit), commonly used to validate commit message format, run linting, or trigger CI. Usually they fire in order on each git commit.

git history split generates commit objects programmatically under the hood, skipping these hooks, so tools relying on commit-msg validation won't see the two messages typed during the split. If your team's compliance checks rely on hooks, verify commit messages manually after splitting, or run the validation script separately.

Before splitting, see every step the agent took

Deciding which hunks belong together is the hardest part of splitting; the single commit the agent leaves behind doesn't tell you the order it worked in.

The Hermes Review Desk in By turn view: two turns (T1: 3 files, T2: 1 file), turn 1's diff of src/db.ts, and a commit message drafted from the turns.

Hermes IDE runs each agent (Claude Code, Codex, etc.) in its own terminal and saves every agent turn, so you can diff or restore any single turn. Review Desk (⌘G on macOS, Ctrl+Shift+G on Windows and Linux) shows these changes by turn or by file, with risk markers.

If the agent did the zero-padding fix in the first turn and the refactor in the second, the by-turn view shows you the pathspec git history split needs before you type the command. If you open Review Desk before the agent commits, you can stage and commit by file right there and skip splitting altogether. Inline comments left on a turn go back to the agent that wrote it, so the suggestion "keep the test rewrite and the refactor together" reaches the right terminal.

Disclosure: Hermes IDE is the project of this article's author, so weigh the relevant section accordingly. It's free, source-available (BSL 1.1), supports macOS, Windows, and Linux, and has no affiliation with Nous Research, Anthropic, OpenAI, or any other agent vendor.

#git history split#Git 2.54#interactive rebase#AI coding agent#git add -p#git history reword#history rewriting
Share:

Related articles