|

feat: add mercurial-history-rewriting skill

Author: Chris Tusa <chris.tusa@leafscale.com>
Date: May 03, 2026 15:52
Changeset: 48ca9ffea549708ae356b2e7c331d04d1da913de
Branch: default

Diff

diff -r 6d95040ca361 -r 48ca9ffea549 skills/mercurial-history-rewriting/SKILL.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/skills/mercurial-history-rewriting/SKILL.md	Sun May 03 15:52:17 2026 -0500
@@ -0,0 +1,128 @@
+---
+name: mercurial-history-rewriting
+description: Use when rewriting Mercurial history — amending commits, uncommitting, splitting commits, or recovering from a mistake. Critical: only safe on draft changesets, never on public ones.
+---
+
+# Mercurial history rewriting
+
+## When this applies
+
+Use when:
+- About to amend a commit (fix typo, add forgotten file, edit the message).
+- Need to uncommit / split a changeset.
+- Recovering from a mistaken commit.
+
+Do not use for:
+- Routine commits → see `mercurial-basics`.
+- Bookmark/PR push flow → see `mercurial-bookmarks-and-prs`.
+- Conflicts after merging → see `mercurial-sync-and-merge`.
+
+## The fundamental rule: draft only
+
+**Only rewrite changesets in `draft` phase. Never rewrite `public` ones.**
+
+Check before rewriting:
+
+```sh
+hg phase -r tip                 # or any specific revision
+```
+
+If the phase is `public`, **stop and surface the situation to the user.** Rewriting public history breaks every other clone of the repo. Mercurial will refuse by default with: `cannot amend public changesets`.
+
+In Isurus the repo is non-publishing, so pushed changesets stay `draft` until merged into the canonical branch. That makes `hg amend` safe during code review. After merge, the changesets become `public` and are off-limits.
+
+## `hg amend` — fix the tip changeset in place
+
+The most common rewrite. Edit files, then:
+
+```sh
+hg amend                        # fold working-dir changes into tip; keeps message
+hg amend -m "new message"       # also rewrite the message
+hg amend file1 file2            # only fold those files
+```
+
+After amend, the new changeset has a different hash. If it was already pushed, you'll need `-f` next push:
+
+```sh
+hg push -B my-feature -f
+```
+
+This is normal in a non-publishing repo. See `mercurial-bookmarks-and-prs` for the post-amend push pattern.
+
+## `hg uncommit` — undo a commit, keeping changes in working dir
+
+```sh
+hg uncommit                     # the entire tip changeset
+hg uncommit file1 file2         # only those files (rest stay committed)
+```
+
+Use cases:
+- The commit message is wrong and you want to redo it from scratch.
+- You committed too much and want to split.
+
+After uncommit, the files are back in the working dir as uncommitted changes. Re-commit selectively.
+
+## Splitting a commit
+
+Goal: turn one commit into two (or more) more focused ones.
+
+```sh
+hg uncommit                                # uncommit everything
+hg commit path/to/group-1 -m "feat: part 1"
+hg commit path/to/group-2 -m "feat: part 2"
+```
+
+If groups overlap by line within a single file, you may need to use a partial-add tool — that's beyond v1 scope. Manually patch and recommit, or use `hg commit -i` (interactive) if available.
+
+## Recovering from a mistake
+
+### "I committed too soon / wrong message"
+
+```sh
+hg amend -m "the right message"
+```
+
+### "I committed to the wrong bookmark"
+
+```sh
+hg bookmarks                            # see what's where
+hg bookmark wrong-name -r .~1           # move the wrong bookmark back one
+hg bookmark right-name -r .             # put the right bookmark on tip
+```
+
+### "I committed something I shouldn't have"
+
+If only the most recent commit is wrong and changes haven't been pushed:
+
+```sh
+hg uncommit                             # changes return to working dir
+# discard them (CAREFUL — destructive):
+hg revert --all --no-backup             # discard all working-dir changes
+```
+
+### "I want to undo the last several local commits"
+
+This is harder in vanilla Mercurial without `evolve`. Options:
+
+1. `hg strip <rev>` — removes a changeset and all descendants. Requires the `strip` extension (`[extensions] strip = ` in `~/.hgrc`). Destructive; backups are saved in `.hg/strip-backup/` by default.
+2. Re-clone from the remote, lose local changes.
+
+In Isurus today, prefer option 1 with the strip extension. For complex multi-commit rewrites, this is exactly the case where `evolve` + `topics` would help (deferred to phase 2).
+
+## What `hg rollback` is and isn't
+
+`hg rollback` undoes the most recent transaction (commit, pull, push). It's mostly deprecated because it operates on the *transaction*, not the changeset, and quietly loses information. **Prefer `hg amend` / `hg uncommit` / `hg strip` instead.** The repo's `[ui] rollback = false` is recommended (and is the default in modern Mercurial).
+
+## Public-changeset attempts
+
+If an `hg amend` returns:
+
+```
+abort: cannot amend public changesets: <hash>
+```
+
+Do not use `--force` to override. Stop and surface the situation: someone (or the workflow) has marked this changeset public, which means it's been integrated. The right answer is a *new* commit on top, not a rewrite.
+
+## A note on evolve / topics
+
+Modern Mercurial (with the `evolve` extension and `topics`) supports rich history rewriting workflows: stable obsolescence markers, topic branches, automatic descendant rebasing. Isurus does not enable these today; if it does in a future version, this skill will grow a sibling (`mercurial-evolve`) or be expanded.