# Rewrite Aggressively

> Rebase out the branch's earlier changelog commits and regenerate its entries fresh; commits only with --commit

- Skill: `tony/rewrite-aggressively` (Agent Skill)
- Install (CLI): `npx skillmds@latest add tony/rewrite-aggressively`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tony/rewrite-aggressively/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tony (https://skillmd.com/u/tony)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tony/rewrite-aggressively

---



# 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.

