This page is primarily intended for developers of Mercurial.


1. Problem Statement

The Mercurial community has been struggling for years to define a nice way to handle 'topic' branches (sometimes also called 'feature' branches), especially when it comes to sharing them with other people (mainly for code review or other collaboration.)

Bookmarks are a clone of git's refs, which seems to work more poorly in Mercurial than they do in Git, in part because the synchronization parts of bookmarks aren't really done. Adding the remaining bits of git's refs to Mercurial has been controversial, and may represent enough of a behavior change that it's infeasible.

Named branches are visible forever in the revision history, which makes them unsuitable for feature branch work as the feature branch names rapidly pollute the output of things like hg branches.

2. Current Target

This describe the target semantic and behavior for topics. Of course some adjustement can be built.

2.1. General semantics

TL;DR; topic are an extra "light-branch" data relevant to draft changesets.

2.2. sub branches, namespacing and representation

(updated on 2021-10-08, as the namespacing subject is moving forward)

The question is then "how to separate the various elements? The : character has been tempting, but is usage in revsets make it unsuitable for a final UI.

The current plan is to use // (two consecutive forward slashes). Examples:

2.2.1. Use cases for topic namespaces

A study on the actual usage of / as branch names in real life repositories has been conducted, using the Software Heritage public archive. Here are the results:

We should now

2.2.3. Additional notational shortcuts for the command-line

This is not meant for revsets.


2.2.4. Implementation of namespaces and commands

2.3. General effect on named branch

Changeset with topic are only aspiring to be part of the named branch, but not fully in that branch yet. When you have branch foo name foo is resolved to the heads of foo with no topic.

There is a couple of examples:

Multiple heads are not longer ambiguous,

Partial data does not have radical change on the definition,

Usual traversal rules apply:

2.4. Behavior for update

(This implies change in hg update behavior (but are not super relevant))

2.4.1. Case 1: active branch

2.4.2. Case 2: active topic

2.4.3. Case 3: active topic, lagging behind

W was on topic bar, but it is now public so bar does not apply to W. However, the working copy is still having an active topic.

Classical case for getting in that situation is to hg up bar that bring you on W with bar active, then pull that bring you B, C, X, Y and turn W public.

The intent here is to work on topic bar and hg update should make you up-to-date in the bar context.

Alternatively we could requires more data from the user.

2.4.4. Case 4: active topic, topic is closed

W was on topic bar, but it is now public so bar does not apply to W anymore.

Classical case for getting in that situation is to be working on topic bar then bar got 'accepted' and get public. As you former bar is not the new head of foo, people merge/rebase and publish more changesets on top of that.

In that case inferring that you topic is "done" and being up to date mean "bring me to the latest of my branch" seems to make sense.

A possible issue, hg update; hg pull can provide different from hg pull; hg update, in the case where hg update is bringing changeset on the bar topic again.

Alternatively we could not update, pointing at a command to disable the topic.

2.5. Behavior for push to publishing (default)

Mercurial will keep enforcing a single head for each name:

2.5.1. Case A: pushing multiple topological branch

Pushing the following to a publishing server would make X and Y public, fading their bar topic making them plain member of branch foo, creating a new head.

2.5.2. Case B: pushing a merged topic

User can then merge/rebase

push is accepted, all X, Y, Z changeset become public and new single head of branch foo in Z.

2.5.3. Case C: linear push but remote unsynched heads



Push fail as Y creating a new head on branch foo.

User have to pull and merge as usual.

2.5.4. Case D: linear push while in sync


2.5.5. Case E: new named branch

2.6. Behavior for push to non-publishing repo

2.6.1. New topic


2.6.2. New topic on a topological branch (1)

2.6.3. New topic on a topological branch (2)

2.6.4. New topic on a topological branch (3)



2.6.5. New head on topic

2.6.6. Conflicting unrelated topic



2.6.7. New head on branch



fail, creating new head B on branch foo

2.6.8. New topic on new branch

2.7. Behavior for merge

(We won't discuss hg rebase, assuming it will behave the same in 3.7)

2.7.1. Two heads on topic

2.7.2. Topic has three heads

2.7.3. Topic has one head and include branch head


2.7.4. Topic has one head and is behind compared to branch head

2.7.5. Topic has one head, branch has multiple heads

2.8. Stacked diffs workflow

2.9. User Transition

3. Pro and Cons

4. Other questions

5. Open ideas

This is a list of idea that emerged while brainstorming. This served as base for the current things.

6. Current Implementation

Assign topics to non-public changesets. A topic is like a named branch, in that it is a label stored in a changeset's extra, but that topics just disappear when the change moves to public phase (the data still exists, it's just not shown.)

Code is available at

6.0.1. Non-Goals

6.1. Open Questions

7. See also

CategoryDeveloper and CategoryNewFeatures

TopicPlan (last edited 2021-10-08 14:11:59 by GeorgesRacinet)