feat: add mercurial-history-rewriting skill
Author:
Chris Tusa <chris.tusa@leafscale.com>
Date:
May 03, 2026 15:52
Changeset:
48ca9ffea549708ae356b2e7c331d04d1da913de
Branch:
default
Changed files:
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.