Mercurial > public > mercurial-scm > evolve
diff hgext3rd/topic/__init__.py @ 5601:3946ee4ee3ae
topic: add a `exp?.topic.linear-merge` option to allow some oedipus
If this option is set to `from-branch`, a user can call `hg merge some-topic`
from a bare branch even if `some-topic` is a direct descendant of the current
working copy parents. This was previously denied if the changesets was on the
same branch, since the result would be an "oedipus merge".
Some user have been requesting this, and this type of merge is one of Gitlab
standard way of merging a "Merge Request". That new option will unlock issue
`heptapod#200` and make this mode available for those who wants it.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Wed, 14 Oct 2020 15:48:37 +0200 |
parents | 3b7df91c2ba7 |
children | eb326644dc29 |
line wrap: on
line diff
--- a/hgext3rd/topic/__init__.py Thu Oct 15 19:46:38 2020 +0200 +++ b/hgext3rd/topic/__init__.py Wed Oct 14 15:48:37 2020 +0200 @@ -123,6 +123,36 @@ [experimental] topic.server-gate-topic-changesets = yes + +Explicitly merging in the target branch +======================================= + +By default, Mercurial will not let your merge a topic into its target branch if +that topic is already based on the head of that branch. In other word, +Mercurial will not let your create a merge that will eventually have two +parents in the same branches, one parent being the ancestors of the other +parent. This behavior can be lifted using the following config:: + + [experimental] + topic.linear-merge = allow-from-bare-branch + +When this option is set to `allow-from-bare-branch`, it is possible to merge a +topic branch from a bare branch (commit an active topic (eg: public one)) +regardless of the topology. The result would typically looks like that:: + + @ summary: resulting merge commit + |\\ branch: my-branch + | | + | o summary: some more change in a topic, the merge "target" + | | branch: my-branch + | | topic: my-topic + | | + | o summary: some change in a topic + |/ branch: my-branch + | topic: my-topic + | + o summary: previous head of the branch, the merge "source" + | branch: my-branch """ from __future__ import absolute_import @@ -239,6 +269,9 @@ configitem(b'experimental', b'topic.server-gate-topic-changesets', default=False, ) + configitem(b'experimental', b'topic.linear-merge', + default="reject", + ) def extsetup(ui): # register config that strictly belong to other code (thg, core, etc) @@ -1288,7 +1321,37 @@ isrebase = False ist0 = False try: - ret = orig(repo, node, branchmerge, force, *args, **kwargs) + mergemode = repo.ui.config(b'experimental', b'topic.linear-merge') + + cleanup = lambda: None + oldrepo = repo + if mergemode == b'allow-from-bare-branch' and not repo[None].topic(): + unfi = repo.unfiltered() + oldrepo = repo + old = unfi.__class__ + + class overridebranch(old): + def __getitem__(self, rev): + ret = super(overridebranch, self).__getitem__(rev) + if rev == node: + b = ret.branch() + t = ret.topic() + if t: + ret.branch = lambda: b'%s//%s' % (b, t) + return ret + unfi.__class__ = overridebranch + if repo.filtername is not None: + repo = unfi.filtered(repo.filtername) + + def cleanup(): + unfi.__class__ = old + + try: + ret = orig(repo, node, branchmerge, force, *args, **kwargs) + finally: + cleanup() + repo = oldrepo + if not hastopicext(repo): return ret # The mergeupdatewrap function makes the destination's topic as the