Recomposing Commits
Restructure messy branch history into logical commits using worktree isolation and a mandatory review gate.
Recomposing Commits
Use when commits on a feature branch are WIP-messy, mix unrelated changes, or need to be split/merged/reordered before a PR. The original branch is never touched until you explicitly approve the new history — worktree isolation and the review gate are non-negotiable even if you say "just do it."
The skill exists to prevent the common failure mode of rewriting history directly on the branch, losing work, or producing a diff that looks right statistically but differs in content.
When to use
- Commits are WIP/messy and a PR is coming.
- Multiple unrelated changes were mixed into the same commits.
- Commit messages are vague ("fix", "WIP", "stuff").
- Commits need to be split, merged, or reordered.
When to skip
- History is already clean.
- Only one commit to restructure.
- You are on a protected/shared branch — refuse instead of working around it.
How to apply
Safety check first. Refuse immediately if on production, release, release/*, or hotfix/*.
Steps:
git log --oneline— show current history, ask for the start SHA.- Compute base:
BASE=$(git rev-parse <sha>^) git diff $BASE HEAD— read all diffs, identify logical groups, flag overlapping files.- Create worktree with an absolute path (branch names with slashes break relative paths):
WORKTREE_PATH="$REPO_ROOT/.git/recompose/$BRANCH_NAME" git worktree add "$WORKTREE_PATH" -b "recompose/$BRANCH_NAME" - Collapse in the worktree:
git -C "$WORKTREE_PATH" reset --mixed $BASE - Stage and commit each logical group. Use
git -C "$WORKTREE_PATH"for every command — shell state does not persist between tool calls,cdis unreliable. - For overlapping files, use
git add -p(hunk-by-hunk). Nevergit rebase -iorgit add -i— both require a TTY and will hang. - Verify before review gate:
diff <(git diff $BASE HEAD) <(git -C "$WORKTREE_PATH" diff $BASE HEAD)— stats alone are not enough, byte-for-byte match only. - Present the mandatory review gate. Wait for explicit approval before touching the original branch.
- On approval:
git -C "$REPO_ROOT" reset --hard "recompose/$BRANCH_NAME", then remove worktree and branch.
Do not git checkout $BRANCH_NAME before the reset — the branch is already in use by the main worktree and the checkout will fail.
Output should feel like
- Clean logical commits, each with a clear conventional message.
- Original branch history replaced only after explicit user sign-off.
- Worktree cleaned up, no leftover
recompose/*branches.
Related
- git-conventions — commit message format the recomposed history should follow.
- skills-index — vault catalog.