Installs into .claude/skills of the current project.
Are you the author of Rewrite Aggressively?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tony-rewrite-aggressively)
---
name: rewrite-aggressively
description: Rebase out the branch's earlier changelog commits and regenerate its entries fresh; commits only with --commit
allowed-tools: ["Bash", "Read", "Grep", "Glob", "Edit", "AskUserQuestion"]
argument-hint: "[--commit] [optional additional context about the changes]"
user-invocable: true
disable-model-invocation: true
---
# Rewrite Changelog Entries Aggressively
Remove the changelog commits this branch accumulated, then regenerate
its entries from the branch's **current net change**. With `--commit`,
the regenerated entries land as one fresh commit at the tip; otherwise
they are left as an uncommitted edit for the user to commit. Where
`/changelog:refresh` stacks a correcting commit on top,
`/changelog:rewrite-aggressively` rewrites the branch so its changelog
history collapses to a single clean commit.
Hard scope rule: only the branch's own changelog content is rewritten.
Changelog content from the base branch — earlier releases, or
unreleased entries from other work — is never modified. The branch's
**code** history is never modified either; only changelog commits are
touched.
Additional context from user: $ARGUMENTS
---
## Phase 1: Safety checks and scope
1. **Preconditions** — refuse to proceed (report why) if any fail:
- Working tree dirty (`git status --porcelain` non-empty)
- Detached HEAD, or an in-progress rebase/merge/cherry-pick
- Currently on the base/trunk branch
2. **Detect the base.** If the branch has a PR
(`gh pr view --json baseRefName`), the base is its `baseRefName` —
stack-aware. Otherwise detect trunk via
`git symbolic-ref refs/remotes/origin/HEAD` (fall back to `master`).
3. **Find the changelog file** the same way `/changelog` does (scan for
`CHANGES`, `CHANGES.md`, `CHANGELOG.md`, `HISTORY.md`, `NEWS.md`, …).
4. **Partition the branch's commits** touching the changelog file
(`git log origin/<base>..HEAD --format='%h %s' -- <changelog-file>`):
- **Pure changelog commits** — the commit's diff touches only the
changelog file. These will be dropped in Phase 2.
- **Mixed commits** — changelog hunks entangled with code changes.
These cannot be dropped wholesale. Ask via `AskUserQuestion` how
to handle each: leave the commit intact and let the new tip
commit supersede its entries (recommended — no code history
rewrite), or abort so the user can split the commit first.
- No changelog commits at all → nothing to rewrite; suggest
`/changelog` (or `/changelog:refresh`) and stop.
5. **Pushed-branch gate.** If the branch exists on the remote and the
commits to drop are pushed, warn that completing the rewrite will
require the **user** to `git push --force-with-lease` afterwards,
and get explicit confirmation before rewriting. This command never
pushes.
6. **Back up.** Record the current tip and create a backup branch:
```
git branch changelog-rewrite-backup-$(date -u +%Y%m%d-%H%M%SZ)
```
Report the backup branch name and SHA to the user.
## Phase 2: Rebase out the old changelog commits
1. Drop the pure changelog commits non-interactively with a scripted
sequence editor — for example, turning their `pick` lines into
`drop` by SHA. With GNU coreutils:
```
GIT_SEQUENCE_EDITOR='sed -i -E "s/^pick (<sha1>|<sha2>)/drop \1/"' git rebase -i origin/<base>
```
On BSD/Darwin, `-i` requires an explicit backup suffix; without the
empty one it consumes `-E` as the suffix and litters the rebase
directory:
```
GIT_SEQUENCE_EDITOR='sed -i "" -E "s/^pick (<sha1>|<sha2>)/drop \1/"' git rebase -i origin/<base>
```
Use each dropped commit's abbreviated SHA exactly as it appears in
the todo list. On conflict, stop and show the state — never resolve
by discarding user code.
2. **Verify the invariant** before going further:
- Code unchanged:
`git diff <backup> HEAD -- . ':(exclude)<changelog-file>'` must be
empty (mixed commits kept intact keep this true by construction).
- If only pure commits were dropped and no mixed commits exist,
`git diff origin/<base> HEAD -- <changelog-file>` must now be
empty.
If either check fails, restore (`git reset --hard <backup>`), report,
and stop.
## Phase 3: Regenerate entries fresh
Read the sibling command file
`../changelog/SKILL.md` and apply its rules
verbatim — the *Core Constraint* (a branch is not a release), Phase 1
convention detection, Phase 2 commit categorization, Phase 3 entry
generation and voice, and its Phase 4 presentation gate — including the
per-entry voice check. Generate entries from the branch's current net
change against `origin/<base>`.
One exception: the sibling's Phase 4 offers the commit as a choice at
its approval panel. That choice does not carry here. `--commit` decides
what lands, it was passed or not before the rebase ran, and re-asking
after a history rewrite invites a yes that means something different
from the one the sibling collects.
Entries superseding a mixed commit's surviving changelog hunks may
update those hunks — they are branch-owned content — but nothing from
the base branch.
## Phase 4: Present, edit, commit
**Mandatory gate — never edit or commit without explicit approval.**
1. Present: the summary line
(`Branch: <name> | Base: <base> | Dropped: <shas> | Backup: <branch>`),
the proposed entries as exact markdown, the insertion point, and the
`Target: unreleased section` line. This skill never touches version
headings or version files.
2. On approval, apply with the Edit tool. **With `--commit`** in
`$ARGUMENTS`, commit **once** at the tip, following the commit
message rules in the sibling command's *Commit message conventions
for CHANGES edits* — project convention first, fallback
`docs(CHANGES) <what the update covers>`, never a version, never a
`#N` in the message. Stage the changelog file explicitly by path —
never `git add -A`. **Without `--commit`** (the default), leave the
edit uncommitted and show a ready-to-use commit message built from
the same rules — committing is the user's decision, as with
`/changelog`.
3. Close by reporting: the backup branch to delete once satisfied
(`git branch -D <backup>`), that an uncommitted changelog edit is
awaiting the user's commit (when `--commit` was not passed), and —
if the branch was pushed — that the user needs
`git push --force-with-lease` to publish the rewrite.
---
## Rules
- **Backup before rewrite**: the backup branch is created before any
rebase and its name reported; restoration is one `git reset --hard`.
- **Code history is sacred**: only pure changelog commits are dropped;
mixed commits are never rewritten without an explicit user choice,
and the post-rebase code-diff check must come back empty.
- **Branch-scoped, always**: base-branch changelog content is never
modified.
- **Commits only with `--commit`**: by default the regenerated entries
are left uncommitted with a suggested message; the rebase that drops
old changelog commits still runs (that is the point of this skill),
behind its own confirmation gates.
- **Never pushes**: force-pushing the rewritten branch is the user's
explicit act, flagged in the closing report.
- **A branch is not a release**: all Core Constraint rules from
`/changelog` apply — no version headings, no version predictions, no
version-file edits.
- **Ask on ambiguity**: mixed commits, unclear entry ownership, or a
pushed branch all get a question, not a guess.