1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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.
|