|
root / skills / mercurial-bookmarks-and-prs / SKILL.md
SKILL.md markdown 138 lines 5.8 KB

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

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

hg bookmarks

Output marks the active bookmark with *:

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

Switching bookmarks

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:

hg update -r <revision>

Pushing for review

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

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:

# ... 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:

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):

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.