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
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
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).
Find the changelog file the same way /changelog does (scan for
CHANGES, CHANGES.md, CHANGELOG.md, HISTORY.md, NEWS.md, …).
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.
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.
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
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.
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.
- 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.
- 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.
- 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.
1---2name: rewrite-aggressively3description: Rebase out the branch's earlier changelog commits and regenerate its entries fresh; commits only with --commit4---567# Rewrite Changelog Entries Aggressively89Remove the changelog commits this branch accumulated, then regenerate10its entries from the branch's **current net change**. With `--commit`,11the regenerated entries land as one fresh commit at the tip; otherwise12they are left as an uncommitted edit for the user to commit. Where13`/changelog:refresh` stacks a correcting commit on top,14`/changelog:rewrite-aggressively` rewrites the branch so its changelog15history collapses to a single clean commit.1617Hard scope rule: only the branch's own changelog content is rewritten.18Changelog content from the base branch — earlier releases, or19unreleased entries from other work — is never modified. The branch's20**code** history is never modified either; only changelog commits are21touched.2223Additional context from user: $ARGUMENTS2425---2627## Phase 1: Safety checks and scope28291. **Preconditions** — refuse to proceed (report why) if any fail:30 - Working tree dirty (`git status --porcelain` non-empty)31 - Detached HEAD, or an in-progress rebase/merge/cherry-pick32 - Currently on the base/trunk branch33342. **Detect the base.** If the branch has a PR35 (`gh pr view --json baseRefName`), the base is its `baseRefName` —36 stack-aware. Otherwise detect trunk via37 `git symbolic-ref refs/remotes/origin/HEAD` (fall back to `master`).38393. **Find the changelog file** the same way `/changelog` does (scan for40 `CHANGES`, `CHANGES.md`, `CHANGELOG.md`, `HISTORY.md`, `NEWS.md`, …).41424. **Partition the branch's commits** touching the changelog file43 (`git log origin/<base>..HEAD --format='%h %s' -- <changelog-file>`):44 - **Pure changelog commits** — the commit's diff touches only the45 changelog file. These will be dropped in Phase 2.46 - **Mixed commits** — changelog hunks entangled with code changes.47 These cannot be dropped wholesale. Ask via `AskUserQuestion` how48 to handle each: leave the commit intact and let the new tip49 commit supersede its entries (recommended — no code history50 rewrite), or abort so the user can split the commit first.51 - No changelog commits at all → nothing to rewrite; suggest52 `/changelog` (or `/changelog:refresh`) and stop.53545. **Pushed-branch gate.** If the branch exists on the remote and the55 commits to drop are pushed, warn that completing the rewrite will56 require the **user** to `git push --force-with-lease` afterwards,57 and get explicit confirmation before rewriting. This command never58 pushes.59606. **Back up.** Record the current tip and create a backup branch:61 ```62 git branch changelog-rewrite-backup-$(date -u +%Y%m%d-%H%M%SZ)63 ```64 Report the backup branch name and SHA to the user.6566## Phase 2: Rebase out the old changelog commits67681. Drop the pure changelog commits non-interactively with a scripted69 sequence editor — for example, turning their `pick` lines into70 `drop` by SHA. With GNU coreutils:71 ```72 GIT_SEQUENCE_EDITOR='sed -i -E "s/^pick (<sha1>|<sha2>)/drop \1/"' git rebase -i origin/<base>73 ```74 On BSD/Darwin, `-i` requires an explicit backup suffix; without the75 empty one it consumes `-E` as the suffix and litters the rebase76 directory:77 ```78 GIT_SEQUENCE_EDITOR='sed -i "" -E "s/^pick (<sha1>|<sha2>)/drop \1/"' git rebase -i origin/<base>79 ```80 Use each dropped commit's abbreviated SHA exactly as it appears in81 the todo list. On conflict, stop and show the state — never resolve82 by discarding user code.83842. **Verify the invariant** before going further:85 - Code unchanged:86 `git diff <backup> HEAD -- . ':(exclude)<changelog-file>'` must be87 empty (mixed commits kept intact keep this true by construction).88 - If only pure commits were dropped and no mixed commits exist,89 `git diff origin/<base> HEAD -- <changelog-file>` must now be90 empty.9192 If either check fails, restore (`git reset --hard <backup>`), report,93 and stop.9495## Phase 3: Regenerate entries fresh9697Read the sibling command file98`../changelog/SKILL.md` and apply its rules99verbatim — the *Core Constraint* (a branch is not a release), Phase 1100convention detection, Phase 2 commit categorization, Phase 3 entry101generation and voice, and its Phase 4 presentation gate — including the102per-entry voice check. Generate entries from the branch's current net103change against `origin/<base>`.104105One exception: the sibling's Phase 4 offers the commit as a choice at106its approval panel. That choice does not carry here. `--commit` decides107what lands, it was passed or not before the rebase ran, and re-asking108after a history rewrite invites a yes that means something different109from the one the sibling collects.110111Entries superseding a mixed commit's surviving changelog hunks may112update those hunks — they are branch-owned content — but nothing from113the base branch.114115## Phase 4: Present, edit, commit116117**Mandatory gate — never edit or commit without explicit approval.**1181191. Present: the summary line120 (`Branch: <name> | Base: <base> | Dropped: <shas> | Backup: <branch>`),121 the proposed entries as exact markdown, the insertion point, and the122 `Target: unreleased section` line. This skill never touches version123 headings or version files.1242. On approval, apply with the Edit tool. **With `--commit`** in125 `$ARGUMENTS`, commit **once** at the tip, following the commit126 message rules in the sibling command's *Commit message conventions127 for CHANGES edits* — project convention first, fallback128 `docs(CHANGES) <what the update covers>`, never a version, never a129 `#N` in the message. Stage the changelog file explicitly by path —130 never `git add -A`. **Without `--commit`** (the default), leave the131 edit uncommitted and show a ready-to-use commit message built from132 the same rules — committing is the user's decision, as with133 `/changelog`.1343. Close by reporting: the backup branch to delete once satisfied135 (`git branch -D <backup>`), that an uncommitted changelog edit is136 awaiting the user's commit (when `--commit` was not passed), and —137 if the branch was pushed — that the user needs138 `git push --force-with-lease` to publish the rewrite.139140---141142## Rules143144- **Backup before rewrite**: the backup branch is created before any145 rebase and its name reported; restoration is one `git reset --hard`.146- **Code history is sacred**: only pure changelog commits are dropped;147 mixed commits are never rewritten without an explicit user choice,148 and the post-rebase code-diff check must come back empty.149- **Branch-scoped, always**: base-branch changelog content is never150 modified.151- **Commits only with `--commit`**: by default the regenerated entries152 are left uncommitted with a suggested message; the rebase that drops153 old changelog commits still runs (that is the point of this skill),154 behind its own confirmation gates.155- **Never pushes**: force-pushing the rewritten branch is the user's156 explicit act, flagged in the closing report.157- **A branch is not a release**: all Core Constraint rules from158 `/changelog` apply — no version headings, no version predictions, no159 version-file edits.160- **Ask on ambiguity**: mixed commits, unclear entry ownership, or a161 pushed branch all get a question, not a guess.