Note:
This page is primarily intended for developers of Mercurial.
FeatureBranchesStruggle
The hub for summing up issue with Feature branches and pointing at possible solution.
Contents
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.
1.1. Goals
We need a solution that solve the handling of "in progress" changesets. This solution should provide
easy name/category for all draft in the repository,
sensible default behavior for core commands (update, merge, rebase, histedit, evolve,
- intuitive/simple process to exchange draft with other people (no hg push --force),
- good story for pull request
- good fit with the Mercurial experience an philosophy so far (at at least, its good part)
- usable by all users on a team, even those who are casual users of VCS tooling
1.2. Challenge
The main challenges to get such a feature right are:
- Life cycle:
- Grouping changes and naming the topic branch is usually only relevant while working to get the feature done. We need a natural/efficient way for the topic to fade away when feature are complete. [augie notes that it might be interesting/useful to be able to query the topic name after the topic is done]
- Distributed:
- A good solution for topic branch should work well in a distributed environment, where users may be pulling from each other in arbitrary ways. Topic information must be exchanged at the same time as the commits they reference.
- Clearly defined set of changes:
- A topic is usually composed of multiple changesets. Being able to easily define what is in the set is important for commands that handle topics as a whole (eg histedit and email.) Having a good mechanism for this will probably help produce a better UI in evolution as well. Having a defined set of changesets is also needed when only part of the topic is pushed or pulled.
A topic for a change can't be derived from "its topological branch"+"a bookmark" because sometimes topics will share a root, and sometimes exploring multiple solutions leads to multiple heads on a topic. It can also be confusing when a topic is rebased.]
- Anonymous branching:
- Anonymous branches is a useful feature of Mercurial that adds flexibility and improves productivity. We should keep this strength available within each topic.
- name conflict handling:
- Fixing a bad name (or people fighting over a name) should not result in a very complicated situation (particularly around divergence.)
- Tracking/Target:
- People typically make changes with the goal of getting them integrated into a specific line of development (default, stable, version 4.2, staging, etc). This "target" should be the default destination for merge, rebase, update, etc. This aspect can probably use (or maybe need) integration with the life cycle.
augie notes that he doesn't like the conceptual complexity this introduces
- Handling large number of feature branch:
Having large team collaborating together can lead to very large to feature branch at the same time. Having a way to only see/interract with the one relevant becomes necessary. This is not entirely in the scope of this discussion but closely related.
1.3. Leads for solution
Bookbinder - Turns a bookmark into the equivalent of a topic. Can use -r <bookmark> to get all draft ancestors of <bookmark>.
1.4. Current shortcomings of bookmarks
This plan is not meant as "bookmarks are doomed, lets do something else." The idea here is more driven by "we have some long standing issues with bookmarks, lets think again from scratch and see what emerges." We'll reconcile topics with bookmarks at a later date, once we know what we want. It's entirely possible that bookmarks can grow bits of new functionality and become topics.
There is currently an experimentation around the idea of "remote bookmarks" [TODO(augie): link to a remote bookmarks wiki page] and wider workflow changes, it will be "evaluated" independently. (it's a wiki, please feel free to update the content of this section)
requirements |
in-core |
remote |
Life cycle |
poor |
poor |
distributed |
okay |
bad |
defined set |
poor |
poor |
partial exch |
bad |
okay |
branching |
bad |
bad |
conflict |
okay |
okay |
tracking |
bad |
good |
The lifecycle of bookmarks is problematic because we still have not figured out a good way to handle deletion and renaming. Once in the wild, it is very hard to get rid of a feature related bookmark. [augie and marmoute are not sure if remote-bookmarks improves that.]
Bookmark behavior in the distributed area is okay-ish for the in-core bookmark. The current behavior on pull works in a distributed way: it will exchange any bookmark along with the matching changeset. Behavior on push is problematic as the local bookmark may not be pushed (Mercurial may warn about it, but this is not reliable.)
[TODO(marmoute): work with augie to clarify this sentence] The 'remote-boomarks' change is more problematic in this aspect as remote name are not propagated so changesets can get exchanged without there topic information.
tracking is not covered at all by current core version. It is introduced with 'remote-bookmark' but only covers rebase. Additionally, the UI to configure and observe tracking is unclear to [marmoute] yet.
A bookmark can implicitly define a set of revisions since everything 'only' under that bookmark it can be considered in the topic. This has issues:
- Requires the use of bookmarks for the main branches
- Misbehaves if a some part of the topic is shared with another bookmark
- No way of handling of extra anonymous heads on the same topic
Because they refer to a single changeset at the top of the stack, bookmark are bad at partial exchange. It is often practical to push or to pull only a part of the topic because the rest is not ready yet. Because the bookmark have no "start" the shared changesets are pulled anonymously in this case.
For the same reason (referring to a single revision), bookmarks do not allow for experimental branches within a topic label.
Divergent bookmarks provide a solution for conflict. However it does not handle rewinding a bookmark or deletion/recreation cycles.
1.5. See Also
* Long Gregory Szorc email about MQ usage at Mozilla * https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-June/099821.html