|
root / skills / mercurial-bookmarks-and-prs
mercurial-bookmarks-and-prs Plain Text 138 lines 5.8 KB
  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
129
130
131
132
133
134
135
136
137
---
name: mercurial-bookmarks-and-prs
description: Use when starting feature work, switching between in-progress work, or pushing a feature for review in a Mercurial repo. Bookmarks are the unit of feature work and the unit of pull requests in this workflow.
---

# Mercurial bookmarks and pull requests

## When this applies

Use when:
- Starting a new feature or fix that will become a pull request.
- Switching between multiple in-progress features.
- About to push work for review.
- A bookmark is in the wrong place and needs fixing.

Do not use for:
- Long-lived branches like `default`, `stable` — those are named branches, see "Bookmark vs named branch" below for the distinction.
- Pulling/merging upstream changes → see `mercurial-sync-and-merge`.
- Amending commits before push → see `mercurial-history-rewriting`.

## Bookmark vs named branch

| | Bookmark | Named branch |
|---|---|---|
| Purpose | Feature/PR pointer | Long-lived line of development |
| Lifetime | Days to weeks; deleted after merge | Months to years |
| Examples | `add-language-stats`, `fix-nil-reviewer` | `default`, `stable`, `release-2.0` |
| Moves on commit? | Yes (the active one moves) | The new commit stays on the branch |
| Can be deleted? | Yes (`hg bookmark -d`) | Effectively no |

**Rule of thumb:** if you'd open a PR for it, it's a bookmark. If it's a maintained release line, it's a named branch.

### When the user says "branch"

Most users come to Mercurial from Git, where "branch" means a lightweight pointer that can be deleted. In Mercurial that concept is a **bookmark**, not a named branch. Map their words accordingly:

- **"create a feature branch", "start a branch", "switch branches", "branch off X"** → bookmark, every time.
- **"create a release branch", "branch for v2.0"** → named branch (long-lived release line).
- **Ambiguous** → ask, but default to bookmark for anything PR-shaped.

**Override repo precedent.** If you find existing named branches that look like feature work (e.g. an `add-language-stats` named branch alongside `default`), do *not* infer that the convention is to use named branches. That precedent is almost always a previous mistake (often by an LLM that didn't load this skill). Use a bookmark for the new work and surface the inconsistency:

> "Heads up: this repo has named branches (`add-language-stats`, `fix-nil-reviewer`) that look like feature work, which is unusual — feature work in Mercurial is typically a bookmark. I'm using a bookmark for the new feature; let me know if you'd prefer to match the existing pattern."

The only time existing named branches *should* steer you toward a named branch is when they are clearly long-lived release lines (`stable`, `release-1.0`, `release-2.0`).

## Starting a feature

```sh
hg pull -u                  # sync to latest default
hg bookmark my-feature      # create bookmark at current rev
# ... edit files ...
hg add new-file.go
hg commit -m "feat: add new thing"
hg push -B my-feature       # push the bookmark to the remote
```

After `hg commit`, the bookmark `my-feature` advances to the new changeset automatically (it's the active bookmark).

## Listing bookmarks

```sh
hg bookmarks
```

Output marks the active bookmark with `*`:

```
   add-language-stats        42:a1b2c3d4e5f6
 * my-feature                47:b9c8d7e6f5a4
   work-in-progress          39:c5d4e3f2a1b0
```

## Switching bookmarks

```sh
hg update my-feature        # switch to the bookmark and make it active
```

`hg update` checks out the changeset the bookmark points to AND activates the bookmark (so future commits move it forward).

If you only want to look at a revision without activating any bookmark there:

```sh
hg update -r <revision>
```

## Pushing for review

The Isurus convention (non-publishing repo + bookmarks = PRs):

```sh
hg push -B my-feature
```

`-B my-feature` pushes the bookmark by name. Without `-B`, `hg push` pushes the current head's changesets but does not push the bookmark itself, which means the remote won't know to associate them with a PR.

After pushing, open the PR in the Isurus web UI (or the equivalent forge UI). See `isurus-conventions` for Isurus specifics.

## Updating a PR after review feedback

In a non-publishing repo, pushed changesets stay `draft` until the PR is merged. That means amending after a push is **safe**:

```sh
# ... make the requested changes ...
hg amend                    # rewrites the tip changeset in place
hg push -B my-feature -f    # -f because the rewrite changed the hash
```

The `-f` is required because the new amended changeset has a different hash than what's on the remote; without `-f` the push is rejected. This is the *intended* workflow — not a sign you're doing something dangerous, because the changesets are still draft.

## Deleting a bookmark after merge

Once the PR is merged into `default`:

```sh
hg pull -u                  # pull in the merged changes
hg bookmark -d my-feature   # delete locally
hg push --delete my-feature # delete on the remote (if not already gone)
```

## Recovering a misplaced bookmark

If the bookmark is on the wrong changeset (e.g., you forgot it was active and committed something unrelated):

```sh
hg bookmarks                          # see where it is
hg bookmark my-feature -r <correct>   # move it
```

The `-r` flag moves an existing bookmark to a specific revision without checking out anything.

## Common pitfalls

- **Forgetting `-B` on push:** the changesets land but no bookmark = no PR association. Re-push with `hg push -B <name>`.
- **Forgetting `-f` after amend:** push is rejected with "remote has changesets you don't have." Verify it's your own amended changeset (not a real upstream change), then `-f`.
- **Active bookmark surprise:** `hg update -r <rev>` *without* a bookmark name leaves no bookmark active; subsequent commits create anonymous heads. Always activate a bookmark you intend to commit to.