From ravn-ai-toolkit
Rewrites feature branch commit history into clean conventional commits telling a progressive story. Backs up branch, soft resets, and recommits atomically. Use to clean WIP before PRs, reorganize, or convert formats.
npx claudepluginhub ravnhq/ai-toolkitThis skill is limited to using the following tools:
Rewrite a feature branch's messy commit history into clean, conventional commits that tell a progressive, linear story — safe to read, review, and bisect.
Rewrites Git branch history into clean, narrative-quality commits for code review. Creates backup branch, reimplements changes from main diff, verifies byte-identical, replaces original.
Guides Git workflow management with atomic commits: organizes staging, branching strategies, merge/rebase, PR management, history cleanup, staged analysis. Use for commits, branches, merges.
Commits and pushes code changes using git strategies like squash into existing commits, new commits, or interactive rebase of branch history. Use at implementation completion or on git commit requests.
Share bugs, ideas, or general feedback.
Rewrite a feature branch's messy commit history into clean, conventional commits that tell a progressive, linear story — safe to read, review, and bisect.
Abort if the working tree is dirty. A clean rewrite requires a clean state.
git status --porcelain
If output is non-empty: stop. Tell the user to stash or commit pending changes first.
Then detect the parent branch. The entire rewrite depends on using the correct base — a wrong base means wrong diffs and wrong commits.
git log --oneline --decorate --graph --all | head -20
Check if the branch has commits relative to main:
git log --oneline main..HEAD 2>/dev/null | wc -l
If the count is 0 or the command fails, the branch was likely forked from something other than main. Ask the user to confirm the target branch before proceeding. Do not assume main.
Common alternatives: master, develop, staging, origin/main.
Once confirmed, set the base branch for all subsequent steps:
BASE=<confirmed-branch> # e.g. BASE=main or BASE=develop
Create a timestamped backup branch at the current HEAD before touching anything.
BRANCH=$(git rev-parse --abbrev-ref HEAD)
EPOCH=$(date +%s)
git branch backup/${BRANCH}-${EPOCH}
Confirm backup was created. This is the restore point if anything goes wrong.
Read the full diff and log between the base branch and HEAD.
git log --oneline ${BASE}..HEAD
git diff --stat ${BASE}...HEAD
For large branches (many files), start with --stat to see the scope before reading the full diff. Then read individual files as needed to understand the changes in depth.
git diff ${BASE}...HEAD
Identify the logical units of work. Look for:
Group related changes together. A good commit is one logical unit, not one file.
Present the proposed commit sequence to the user. Each entry must include:
Order commits so each builds on the previous — the branch should compile and make sense at every point.
Example plan format:
1. feat(auth): add JWT token generation
Files: src/auth/token.ts, src/auth/types.ts
2. feat(auth): add login endpoint with token issuance
Files: src/routes/auth.ts, src/routes/auth.test.ts
3. chore: update env example with JWT secret
Files: .env.example
Before confirming, verify every file that appears in git diff --stat ${BASE}...HEAD is assigned to at least one commit in the plan. Unassigned files will cause the tree parity check to fail in Step 6.
Wait for user approval before executing. Accept:
Do not proceed until the user confirms the plan.
Soft-reset to the merge base, then create each commit one at a time with selective staging.
git reset --soft $(git merge-base ${BASE} HEAD)
For each planned commit:
git add <specific files for this commit>
git commit -m "<conventional commit message>"
Use selective git add — never git add -A for a batch. Each commit must contain only its planned files.
After all commits, verify tree parity against the backup:
BRANCH=$(git rev-parse --abbrev-ref HEAD)
# Find the backup branch (most recent for this branch).
# sort works correctly here because the epoch timestamp is always 10 digits (valid until 2286).
BACKUP=$(git branch --list "backup/${BRANCH}-*" | sort | tail -1 | tr -d ' ')
git diff HEAD ${BACKUP}
If diff is non-empty: something was lost or corrupted. Restore immediately:
git reset --hard ${BACKUP}
Report the failure and stop.
Confirm success:
git log --oneline ${BASE}..HEAD shows the new clean historygit diff HEAD ${BACKUP} is empty (tree parity confirmed)| Type | Use for |
|---|---|
feat | New feature or capability |
fix | Bug fix |
refactor | Code change with no behavior change |
test | Adding or updating tests |
docs | Documentation only |
chore | Build, tooling, config, deps |
perf | Performance improvement |
ci | CI/CD changes |
style | Formatting, whitespace (no logic change) |
revert | Reverts a previous commit |
Format: type(scope): subject — subject is imperative, lowercase, no period.
Breaking changes: Append ! after type/scope, e.g. feat(api)!: rename endpoint.
Default base is main. Override with BASE=<branch> before running, or ask the user if uncertain.
Common alternatives: master, develop, staging, origin/main.
User: "Can you clean up my commits before I open this PR? It's a bunch of WIP saves."
Expected behavior: Use this skill. Start with Step 1 (guard check), then proceed through all steps.
User: "Rewrite my commit history into conventional commits."
Expected behavior: Use this skill. Follow the full 7-step workflow.
User: "Write a commit message for my current changes."
Expected behavior: Do not use this skill. Write a single commit message directly.
User: "Squash my last 3 commits into one."
Expected behavior: Do not use this skill. Use git reset --soft HEAD~3 directly and commit.
git status --porcelain returns output before the rewrite starts.git stash) or commit pending changes, then retry.git merge-base ${BASE} HEAD fails or returns unexpected output.git log --oneline to see branch history.git diff HEAD ${BACKUP} is non-empty after all commits are created.git reset --hard ${BACKUP}. Report which files diverged. Re-plan and retry.git branch --list "backup/${BRANCH}-*" returns empty.git branch --list "backup/*" to locate any backup branches. Do not proceed with verification until the backup is confirmed.