# HG changeset patch # User Anton Shestakov # Date 1615444346 -28800 # Node ID d161fccccd804390e46586e67210c95302a811cd # Parent 785b5be835ee6a49e4fa14144e4343072f0a9fb6# Parent 67fc03f42d9293daa8eea2fd95711bbd0bcac9b6 test-compat: merge mercurial-5.0 into mercurial-4.9 # no-check-commit diff -r 785b5be835ee -r d161fccccd80 .hgtags --- a/.hgtags Sun Jan 31 15:57:57 2021 +0800 +++ b/.hgtags Thu Mar 11 14:32:26 2021 +0800 @@ -90,3 +90,5 @@ fb543438704b73b22023a493c9ef76fc8746b796 10.0.1 1cce884c944830a7b331a17fd18614b93cbac987 10.0.2 782cbadb123fe4991e91a03d367e02d0b5ae969c 10.1.0 +35b883a4ff5a97973eb9e6f00014e71f14cebe70 10.2.0 +eadc1d09f2f567fdae7280aefc8cf4cdc4d78cbc 10.2.0.post1 diff -r 785b5be835ee -r d161fccccd80 CHANGELOG --- a/CHANGELOG Sun Jan 31 15:57:57 2021 +0800 +++ b/CHANGELOG Thu Mar 11 14:32:26 2021 +0800 @@ -1,35 +1,54 @@ Changelog ========= -10.1.1 -- in progress ---------------------- +10.3.0 - in progress +-------------------- + + * evolve: add a experimental.evolution.in-memory config for running evolve + in memory (hg >= 5.6) + * evolve: improve content-divergence resolution that involves parent changes + * evolve: preserve wdir parent when using `hg evolve --stop` + * obslog: clarify the command name in the help, + * pdiff, pstatus: drop some irrelevant command flags inherited from `hg diff` + and `hg status` respectively + * rewind: detect and abort on cases when we rewind to changesets that are + precessors / successors of each other + * rewind: when user gives only some parts of a fold, include the other parts + as well, or abort if they are missing from local repo + +10.2.1 - in progress +-------------------- + + * doc: document stack as a substitue for MQ's qseries + +10.2.0.post1 -- 2021-02-01 +-------------------------- + +same content as 10.2.0, but with a valid tarball on pypi. + +10.2.0 -- 2021-02-01 +-------------------- + + * compatibility with Mercurial 5.7 * doc: update the MQ To Evolve guide and fix build warning for index.rst + * evolve: improve resolution of some case of parent divergence + * evolve: respect command-templates.oneline-summary if configured * evolve: remove spurious "working directory is now at ..." messages * evolve: various documentation improvements * packaging: default to building docs on Python 3 -topic: + * strip: remove experimental.prunestrip option + +topic (0.21.0) + + * performance: speed up various operations using an in-memory cache for topic * rebase: prevent in-memory rebase from silently dropping topic (by disabling the feature) -10.2.0 - in progress --------------------- - - * compatibility with Mercurial 5.7 - - * evolve: improve resolution of some case of parent divergence - * evolve: respect command-templates.oneline-summary if configured - - * strip: remove experimental.prunestrip option - -topic: - - * performance: speed up various operations using an in-memory cache for topic - * topic: rework how ctx.branch() is wrapped * topic: look for topic heads only when necessary, this fixes the output of e.g. hg heads when topics are in play diff -r 785b5be835ee -r d161fccccd80 MANIFEST.in --- a/MANIFEST.in Sun Jan 31 15:57:57 2021 +0800 +++ b/MANIFEST.in Thu Mar 11 14:32:26 2021 +0800 @@ -4,6 +4,7 @@ include MANIFEST.in include README.rst include setup.py +recursive-include hgext3rd *.py recursive-include tests *.py *.sh *.t include docs/makefile @@ -18,7 +19,7 @@ exclude docs/tutorial/.netlify exclude .gitlab-ci.yml -exclude ./hgext3rd/evolve/legacy.py +exclude hgext3rd/evolve/legacy.py exclude .hg-format-source exclude Makefile exclude tests/test-drop.t diff -r 785b5be835ee -r d161fccccd80 debian/changelog --- a/debian/changelog Sun Jan 31 15:57:57 2021 +0800 +++ b/debian/changelog Thu Mar 11 14:32:26 2021 +0800 @@ -1,3 +1,15 @@ +mercurial-evolve (10.2.0.post1-1) unstable; urgency=medium + + * identical release + + -- Pierre-Yves David Mon, 01 Feb 2021 12:15:12 +0100 + +mercurial-evolve (10.2.0-1) unstable; urgency=medium + + * new upstream release + + -- Anton Shestakov Mon, 01 Feb 2021 14:43:30 +0800 + mercurial-evolve (10.1.0-1) unstable; urgency=medium * new upstream release diff -r 785b5be835ee -r d161fccccd80 docs/from-mq.rst --- a/docs/from-mq.rst Sun Jan 31 15:57:57 2021 +0800 +++ b/docs/from-mq.rst Thu Mar 11 14:32:26 2021 +0800 @@ -48,6 +48,27 @@ [alias] wip = log -r 'not public()' --template='{rev}:{node|short} {desc|firstline}\n' +Using the topic extension provides another way of looking at your +work in progress. Topic branches are lightweight branches which +fade out when changes are finalized. Although the underlying +mechanics are different, both queues and topics help users +organize and share their unfinished work. The topic extension +provides the ``stack`` command. Similar to ``qseries``, ``stack`` +lists all changesets in a topic as well as other related +information. + +.. code-block:: console + + $ hg stack + +Installing the evolve extension also installs the topic extension. To enable +it, add the following to your `hgrc` config: + +.. code-block:: ini + + [extensions] + topic = + hg qnew ``````` diff -r 785b5be835ee -r d161fccccd80 docs/troubles-handling.rst --- a/docs/troubles-handling.rst Sun Jan 31 15:57:57 2021 +0800 +++ b/docs/troubles-handling.rst Thu Mar 11 14:32:26 2021 +0800 @@ -323,6 +323,21 @@ Set the parent of moved changeset as resolution parent. +Special-case: When parent of moved one is obsolete with a successor +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +By default, evolution will set the successor of obsolete parent as resolution +parent and will relocate both the divergent cset on it to perform 3-way merge. +But if the following config is set to True, it will set the obsolete parent as +resolution parent, so now resolved cset will be orphan, as it will be based on +the obsolete parent. Some users might not like the evolve to automatically +resovle this orphan instability as well (while they only wanted to resolve the +divergence), which is why we are providing this config. + +`experimental.evolution.divergence-resolution-minimal=False(default)` + +(The default resolution that automatically evolve the orphan instability as well +seems the best approach for now, but let's also gather user feedback, then we can decide accordingly) + D-A3.2: both moved forward; same branch """"""""""""""""""""""""""""""""""""""" diff -r 785b5be835ee -r d161fccccd80 docs/tutorial/slides.md --- a/docs/tutorial/slides.md Sun Jan 31 15:57:57 2021 +0800 +++ b/docs/tutorial/slides.md Thu Mar 11 14:32:26 2021 +0800 @@ -761,7 +761,7 @@ But it also has several disadvantages: -- Branches do not disappear once they are merged. You need to explicitely close them with `hg commit --close-branch`. +- Branches do not fade out once they are merged. You need to explicitely close them with `hg commit --close-branch`. - Branches are lost when rebasing them without the `--keepbranches` option of the `hg rebase` command. - New branches needs to be explicitly pushed with the `--new-branch` option of the `hg push` command. @@ -1301,7 +1301,7 @@ #### Topic -Topic branches are lightweight branches which disappear when changes are +Topic branches are lightweight branches which fade out when changes are finalized (move to the public phase). They can help users to organise and share their unfinished work. diff -r 785b5be835ee -r d161fccccd80 hgext3rd/evolve/__init__.py --- a/hgext3rd/evolve/__init__.py Sun Jan 31 15:57:57 2021 +0800 +++ b/hgext3rd/evolve/__init__.py Thu Mar 11 14:32:26 2021 +0800 @@ -52,7 +52,7 @@ evolution.obsdiscovery = yes Obsolescence Markers Discovery -============================== +------------------------------ The evolve extension containts an experimental new protocol to discover common markers between local and remote repositories. @@ -111,7 +111,7 @@ evolution.obsdiscovery = no Effect Flag Experiment -====================== +---------------------- Evolve also records what changed between two evolutions of a changeset. For example, having this information is helpful to understand what changed between @@ -153,8 +153,21 @@ you create will not cause interference with other clients or servers without the effect flag recording. +In-memory Evolve Experiment +--------------------------- + +The :hg:`evolve` command normally creates new changesets by writing the +files to the working copy and then committing them from there. You can +tell it to create the changesets without touching the working copy by +setting this config:: + + [experimental] + evolution.in-memory = yes + +It will still update the working copy in case of conflicts. + Template keywords -================= +----------------- Evolve provides one template keyword that helps explore obsolescence history: @@ -175,6 +188,28 @@ - precursors (deprecated, use predecessors instead) - successors (deprecated, use successorssets instead) - troubles (deprecated, use instabilities instead) + +Revset predicates +----------------- + +Evolve provides several revset predicates: + + - unstable + - troubled (deprecated, use unstable instead) + - suspended + - predecessors + - precursors (deprecated, use predecessors instead) + - allpredecessors + - allprecursors (deprecated, use allpredecessors instead) + - successors + - allsuccessors + +Note that successors revset in evolve is not the same as successors revset in +core Mercurial 4.3+. In evolve this revset returns only immediate successors, +as opposed to all successors. Use "allsuccessors(set)" to obtain all +successors. + +See :hg:`help revsets -v` for more information. """ evolutionhelptext = b""" @@ -241,22 +276,11 @@ [experimental] evolution=all -""".strip() +""" import sys -try: - from mercurial import registrar - registrar.templatekeyword # new in hg-3.8 -except ImportError: - from . import metadata - raise ImportError(b'evolve needs Mercurial version %s or above' % - min(metadata.testedwith.split())) - import mercurial -from mercurial import util - -from mercurial import obsolete from mercurial import ( bookmarks as bookmarksmod, @@ -267,8 +291,9 @@ hg, lock as lockmod, node as nodemod, + obsolete, pycompat, - revset, + util, ) from mercurial.i18n import _ @@ -287,6 +312,7 @@ obsexchange, obshashtree, obshistory, + revset, rewind, safeguard, templatekw, @@ -337,17 +363,20 @@ eh.merge(cmdrewrite.eh) eh.merge(rewind.eh) eh.merge(headchecking.eh) +eh.merge(revset.eh) uisetup = eh.finaluisetup extsetup = eh.finalextsetup reposetup = eh.finalreposetup cmdtable = eh.cmdtable configtable = eh.configtable +templatekeyword = eh.templatekeyword revsetpredicate = eh.revsetpredicate -templatekeyword = eh.templatekeyword # Configuration eh.configitem(b'experimental', b'evolutioncommands', []) eh.configitem(b'experimental', b'evolution.allnewcommands', None) +eh.configitem(b'experimental', b'evolution.divergence-resolution-minimal', False) +eh.configitem(b'experimental', b'evolution.in-memory', b'false') ##################################################################### ### Option configuration ### @@ -402,12 +431,6 @@ del cmdtable[disabledcmd] ##################################################################### -### experimental behavior ### -##################################################################### - -getrevs = obsolete.getrevs - -##################################################################### ### Additional Utilities ### ##################################################################### @@ -426,7 +449,8 @@ def setupparentcommand(ui): _alias, statuscmd = cmdutil.findcmd(b'status', commands.table) - pstatusopts = [o for o in statuscmd[1] if o[1] != b'rev'] + inapplicable = {b'rev', b'change'} + pstatusopts = [o for o in statuscmd[1] if o[1] not in inapplicable] @eh.command(b'pstatus', pstatusopts, **compat.helpcategorykwargs('CATEGORY_WORKING_DIRECTORY')) @@ -442,7 +466,8 @@ return statuscmd[0](ui, repo, *args, **kwargs) _alias, diffcmd = cmdutil.findcmd(b'diff', commands.table) - pdiffopts = [o for o in diffcmd[1] if o[1] != b'rev'] + inapplicable = {b'rev', b'from', b'to', b'change'} + pdiffopts = [o for o in diffcmd[1] if o[1] not in inapplicable] @eh.command(b'pdiff', pdiffopts, **compat.helpcategorykwargs('CATEGORY_WORKING_DIRECTORY')) @@ -464,179 +489,6 @@ b"diff --hidden --rev 'limit(predecessors(.),1)' --rev .", b'evolve') -### Unstable revset symbol - -@eh.revsetpredicate(b'unstable()') -def revsetunstable(repo, subset, x): - """Changesets with instabilities. - """ - revset.getargs(x, 0, 0, b'unstable takes no arguments') - troubled = set() - troubled.update(getrevs(repo, b'orphan')) - troubled.update(getrevs(repo, b'phasedivergent')) - troubled.update(getrevs(repo, b'contentdivergent')) - troubled = revset.baseset(troubled) - troubled.sort() # set is non-ordered, enforce order - return subset & troubled - -@eh.revsetpredicate(b'troubled()') # legacy name -def revsettroubled(repo, subset, x): - return revsetunstable(repo, subset, x) - -### Obsolescence graph - -# XXX SOME MAJOR CLEAN UP TO DO HERE XXX - -def _precursors(repo, s, includeidentical=False): - """Precursor of a changeset""" - cs = set() - getrev = compat.getgetrev(repo.changelog) - markerbysubj = repo.obsstore.predecessors - node = repo.changelog.node - for r in s: - for p in markerbysubj.get(node(r), ()): - if not includeidentical and p[2] & rewind.identicalflag: - continue - pr = getrev(p[0]) - if pr is not None: - cs.add(pr) - cs -= repo.changelog.filteredrevs # nodemap has no filtering - return cs - -def _allprecursors(repo, s): # XXX we need a better naming - """transitive precursors of a subset""" - node = repo.changelog.node - toproceed = [node(r) for r in s] - seen = set() - allsubjects = repo.obsstore.predecessors - while toproceed: - nc = toproceed.pop() - for mark in allsubjects.get(nc, ()): - np = mark[0] - if np not in seen: - seen.add(np) - toproceed.append(np) - getrev = compat.getgetrev(repo.changelog) - cs = set() - for p in seen: - pr = getrev(p) - if pr is not None: - cs.add(pr) - cs -= repo.changelog.filteredrevs # nodemap has no filtering - return cs - -def _successors(repo, s): - """Successors of a changeset""" - cs = set() - node = repo.changelog.node - getrev = compat.getgetrev(repo.changelog) - markerbyobj = repo.obsstore.successors - for r in s: - for p in markerbyobj.get(node(r), ()): - for sub in p[1]: - sr = getrev(sub) - if sr is not None: - cs.add(sr) - cs -= repo.changelog.filteredrevs # nodemap has no filtering - return cs - -def _allsuccessors(repo, s, haltonflags=0): # XXX we need a better naming - """transitive successors of a subset - - haltonflags allows to provide flags which prevent the evaluation of a - marker. """ - node = repo.changelog.node - toproceed = [node(r) for r in s] - seen = set() - allobjects = repo.obsstore.successors - while toproceed: - nc = toproceed.pop() - for mark in allobjects.get(nc, ()): - if mark[2] & haltonflags: - continue - for sub in mark[1]: - if sub == nullid: - continue # should not be here! - if sub not in seen: - seen.add(sub) - toproceed.append(sub) - getrev = compat.getgetrev(repo.changelog) - cs = set() - for s in seen: - sr = getrev(s) - if sr is not None: - cs.add(sr) - cs -= repo.changelog.filteredrevs # nodemap has no filtering - return cs - -##################################################################### -### Extending revset and template ### -##################################################################### - -# this section add several useful revset symbol not yet in core. -# they are subject to changes - - -### XXX I'm not sure this revset is useful -@eh.revsetpredicate(b'suspended()') -def revsetsuspended(repo, subset, x): - """Obsolete changesets with non-obsolete descendants. - """ - revset.getargs(x, 0, 0, b'suspended takes no arguments') - suspended = revset.baseset(getrevs(repo, b'suspended')) - suspended.sort() - return subset & suspended - - -@eh.revsetpredicate(b'predecessors(set)') -def revsetpredecessors(repo, subset, x): - """Immediate predecessors of changesets in set. - """ - s = revset.getset(repo, revset.fullreposet(repo), x) - s = revset.baseset(_precursors(repo, s)) - s.sort() - return subset & s - - -@eh.revsetpredicate(b'precursors(set)') # legacy name for predecessors -def revsetprecursors(repo, subset, x): - return revsetpredecessors(repo, subset, x) - - -@eh.revsetpredicate(b'allpredecessors(set)') -def revsetallpredecessors(repo, subset, x): - """Transitive predecessors of changesets in set. - """ - s = revset.getset(repo, revset.fullreposet(repo), x) - s = revset.baseset(_allprecursors(repo, s)) - s.sort() - return subset & s - - -@eh.revsetpredicate(b'allprecursors(set)') # legacy name for allpredecessors -def revsetallprecursors(repo, subset, x): - return revsetallpredecessors(repo, subset, x) - - -@eh.revsetpredicate(b'successors(set)') -def revsetsuccessors(repo, subset, x): - """Immediate successors of changesets in set. - """ - s = revset.getset(repo, revset.fullreposet(repo), x) - s = revset.baseset(_successors(repo, s)) - s.sort() - return subset & s - -@eh.revsetpredicate(b'allsuccessors(set)') -def revsetallsuccessors(repo, subset, x): - """Transitive successors of changesets in set. - """ - s = revset.getset(repo, revset.fullreposet(repo), x) - s = revset.baseset(_allsuccessors(repo, s)) - s.sort() - return subset & s - - ##################################################################### ### Various trouble warning ### ##################################################################### @@ -1095,6 +947,10 @@ False)) # making sure a next commit is formed if result[0] and result[1]: + # If using in-memory merge, _solveone() will not have updated the + # working copy, so we need to do that. + if evolvecmd.use_in_memory_merge(repo) and result[1]: + compat.update(repo[result[1]]) ui.status(_(b'working directory is now at %s\n') % ui.label(bytes(repo[b'.']), b'evolve.node')) return 0 diff -r 785b5be835ee -r d161fccccd80 hgext3rd/evolve/cmdrewrite.py --- a/hgext3rd/evolve/cmdrewrite.py Sun Jan 31 15:57:57 2021 +0800 +++ b/hgext3rd/evolve/cmdrewrite.py Thu Mar 11 14:32:26 2021 +0800 @@ -579,7 +579,7 @@ c.write(fp) fp.seek(0) - oldnode = node.hex(old.node())[:12] + oldnode = node.short(old.node()) message = b'temporary commit for uncommiting %s' % oldnode tempnode = _patchtocommit(ui, repo, old, fp, message, oldnode) return tempnode @@ -1484,7 +1484,7 @@ pickstate.load() pctxnode = pickstate[b'oldpctx'] ui.status(_(b"aborting pick, updating to %s\n") % - node.hex(pctxnode)[:12]) + node.short(pctxnode)) compat.clean_update(repo[pctxnode]) pickstate.delete() return 0 diff -r 785b5be835ee -r d161fccccd80 hgext3rd/evolve/evolvecmd.py --- a/hgext3rd/evolve/evolvecmd.py Sun Jan 31 15:57:57 2021 +0800 +++ b/hgext3rd/evolve/evolvecmd.py Thu Mar 11 14:32:26 2021 +0800 @@ -32,6 +32,8 @@ util, ) +from mercurial.utils import stringutil + from mercurial.i18n import _ from . import ( @@ -164,7 +166,7 @@ progresscb() with state.saver(evolvestate, {b'current': orig.node()}): newid = _relocate(repo, orig, target, evolvestate, pctx, - keepbranch, b'orphan') + keepbranch, b'orphan', update=False) return (True, newid) def _solvephasedivergence(ui, repo, bumped, evolvestate, display, @@ -316,7 +318,7 @@ otherp1 = succsotherp1 = other.p1().rev() divp1 = succsdivp1 = divergent.p1().rev() - basep1 = base.p1().rev() + basep1 = succsbasep1 = base.p1().rev() # finding single successors of divp1 and otherp1 try: @@ -334,7 +336,7 @@ ui.write_err(msg) return (False, b".") try: - utility._singlesuccessor(repo, base.p1()) + succsbasep1 = utility._singlesuccessor(repo, base.p1()) except utility.MultipleSuccessorsError: msg = (b"ambiguous orphan resolution parent for " b"%s (base)\n") % base @@ -343,43 +345,41 @@ # the changeset on which resolution changeset will be based on resolutionparent = succsdivp1 - # divonly: non-obsolete csets which are topological ancestor of "divergent" - # but not "other" - divonly = repo.revs(b"only(%d, %d) - obsolete()" % (divergent.rev(), - other.rev())) - # otheronly: non-obsolete csets which are topological ancestor of "other" - # but not "div" - otheronly = repo.revs(b"only(%d, %d) - obsolete()" % (other.rev(), - divergent.rev())) - # make it exclusive set - divonly = set(divonly) - {divergent.rev()} - otheronly = set(otheronly) - {other.rev()} - # testing how both the divergent changesets are arranged, there can be 4 # possible cases here: # - # 1) both have the same parents - # 2) both have different parents but greatest common anscestor of them is - # parent of one of them - # 3) both have different parents and gca is not parent of any of them - # 4) one of them is parent of other + # 1) both have the same parent (or parent's successor) + # 2) one of them is parent of other + # 3) one of them moved elsewhere + # 4) both of them moved elsewhere # - # we are handling 1) very good now. - # for 2) we will relocate one which is behind to the parent of ahead one and - # then solve the content-divergence the way we solve 1) - # for 3) and 4), we still have to decide + # we are handling 1) 2) 3) very well now. + # for 4), we still have to decide if otherp1 == divp1: # both are on the same parents pass elif divergent == other.p1(): # both are in parent-child relation pass - elif basep1 in (divp1, otherp1): - # only one side moved, set parent of moved one as resolution parent - if basep1 == divp1: + elif succsbasep1 in (succsdivp1, succsotherp1): + # 1) either, only one side moved + # -> set parent of moved one as resolution parent + # 2) or, both moved but one moved to succs of basep1 + # -> set parent of other one as resolution parent + # 3) or, both have same parent's successor + # -> set parent's successor as resolution parent + if succsbasep1 == succsdivp1: resolutionparent = succsotherp1 else: pass + # a special case of 3) where parent of moved one is obsolete with a + # successor. Also, look at section 'D-A3.1' in troubles-handling.rst + minimal_resolution = ( + ui.configbool(b'experimental', b'evolution.divergence-resolution-minimal') + and succsdivp1 == succsotherp1 and basep1 in (divp1, otherp1) + ) + if minimal_resolution: + resolutionparent = otherp1 if basep1 == divp1 else divp1 else: # the nullrev has to be handled specially because -1 is overloaded to both # mean nullrev (this meaning is used for the result of changectx.rev(), as @@ -390,22 +390,7 @@ gca = [nodemod.nullrev] else: gca = repo.revs(b"ancestor(%d, %d)" % (succsotherp1, succsdivp1)) - - if succsotherp1 in gca and succsdivp1 in gca: - # both are not on the same parent but have same parents's succs. - if otheronly and divonly: - # case: we have visible csets on both side diverging from - # tca of "divergent" and "other". We still need to decide what - # to do in this case - pass - if otheronly: - resolutionparent = succsotherp1 - elif divonly: - pass - else: - # no extra cset on either side - pass - elif succsotherp1 in gca and succsdivp1 not in gca: + if succsotherp1 in gca and succsdivp1 not in gca: pass elif succsdivp1 in gca and succsotherp1 not in gca: resolutionparent = succsotherp1 @@ -588,11 +573,11 @@ assert local != other if local not in repo[None].parents(): repo.ui.note(_(b"updating to \"local\" side of the conflict: %s\n") % - local.hex()[:12]) + local) compat.update(local) # merging the two content-divergent changesets repo.ui.note(_(b"merging \"other\" %s changeset '%s'\n") % - (TROUBLES['CONTENTDIVERGENT'], other.hex()[:12])) + (TROUBLES['CONTENTDIVERGENT'], other)) if progresscb: progresscb() with state.saver(evolvestate): @@ -896,29 +881,18 @@ ordering.extend(sorted(dependencies)) return ordering -def _relocate(repo, orig, dest, evolvestate, pctx=None, keepbranch=False, - category=None): - """rewrites the orig rev on dest rev +def _rewrite_commit_message_hashes(repo, commitmsg): + """filter a commit description to update has to their successors + + The goal of this function is to avoid description referencing obsolete + hashes when a stack is rewritten or evolved. - returns the node of new commit which is formed + Each hash in the description will be detected and, if matching an obsolete + changeset, it will be replaced by its successors. + + Note: They might be case were such behavior might be is wrong, for example + if the commit message is explicitely referencing an older, obsolete changesets. """ - if orig.rev() == dest.rev(): - msg = _(b'tried to relocate a node on top of itself') - hint = _(b"This shouldn't happen. If you still need to move changesets, " - b"please do so manually with nothing to rebase - working " - b"directory parent is also destination") - raise error.ProgrammingError(msg, hint=hint) - - if pctx is None: - if len(orig.parents()) == 2: - msg = _(b"tried to relocate a merge commit without specifying which " - b"parent should be moved") - hint = _(b"Specify the parent by passing in pctx") - raise error.ProgrammingError(msg, hint) - pctx = orig.p1() - - commitmsg = orig.description() - cache = {} sha1s = re.findall(sha1re, commitmsg) unfi = repo.unfiltered() @@ -940,17 +914,87 @@ else: repo.ui.note(_(b'The stale commit message reference to %s could ' b'not be updated\n') % sha1) + return commitmsg + +def use_in_memory_merge(repo): + try: + from mercurial import mergestate as mergestatemod + mergestatemod.memmergestate + except (AttributeError, ImportError): + # no in-memory evolve if Mercurial lacks the required code + # hg <= 5.5 (19590b126764) + return False + config_value = repo.ui.config(b'experimental', b'evolution.in-memory') + if config_value == b'force': + return True + if repo.ui.hasconfig(b'hooks', b'precommit'): + return False + return stringutil.parsebool(config_value) + +def _relocate(repo, orig, dest, evolvestate, pctx=None, keepbranch=False, + category=None, update=True): + """rewrites the orig rev on dest rev + + Also updates bookmarks and creates obsmarkers. + + returns the node of new commit which is formed + """ + if orig.rev() == dest.rev(): + msg = _(b'tried to relocate a node on top of itself') + hint = _(b"This shouldn't happen. If you still need to move changesets, " + b"please do so manually with nothing to rebase - working " + b"directory parent is also destination") + raise error.ProgrammingError(msg, hint=hint) + + if pctx is None: + if len(orig.parents()) == 2: + msg = _(b"tried to relocate a merge commit without specifying which " + b"parent should be moved") + hint = _(b"Specify the parent by passing in pctx") + raise error.ProgrammingError(msg, hint) + pctx = orig.p1() + + commitmsg = _rewrite_commit_message_hashes(repo, orig.description()) tr = repo.currenttransaction() assert tr is not None if repo._activebookmark: repo.ui.status(_(b"(leaving bookmark %s)\n") % repo._activebookmark) bookmarksmod.deactivate(repo) - nodenew = _relocatecommit(repo, orig, dest, pctx, keepbranch, commitmsg) + nodenew = _relocatecommit(repo, orig, dest, pctx, keepbranch, commitmsg, + update) _finalizerelocate(repo, orig, dest, nodenew, tr, category, evolvestate) return nodenew -def _relocatecommit(repo, orig, dest, pctx, keepbranch, commitmsg): +def _relocatecommit(repo, orig, dest, pctx, keepbranch, commitmsg, update): + extra = dict(orig.extra()) + if b'branch' in extra: + del extra[b'branch'] + extra[b'rebase_source'] = orig.hex() + targetphase = max(orig.phase(), phases.draft) + configoverrides = { + (b'phases', b'new-commit'): targetphase + } + with repo.ui.configoverride(configoverrides, source=b'evolve'): + if not update and use_in_memory_merge(repo): + try: + return _relocatecommitinmem( + repo, orig, dest, pctx, keepbranch, commitmsg, extra + ) + except error.InMemoryMergeConflictsError: + repo.ui.status( + b'hit merge conflicts; retrying merge in working copy\n') + return _relocatecommitondisk(repo, orig, dest, pctx, keepbranch, + commitmsg, extra) + +def _relocatecommitondisk(repo, orig, dest, pctx, keepbranch, commitmsg, extra): + """rewrites the orig rev on dest rev on disk + + Creates the new commit by using the old-fashioned way of creating + commits by writing files to the working copy. + + returns the node of new commit which is formed + """ if repo[b'.'].rev() != dest.rev(): compat._update(repo, dest, branchmerge=False, force=True) if keepbranch: @@ -971,19 +1015,50 @@ raise error.InterventionRequired(_(b"unresolved merge conflicts"), hint=hint) - extra = dict(orig.extra()) - if b'branch' in extra: - del extra[b'branch'] - extra[b'rebase_source'] = orig.hex() + # Commit might fail if unresolved files exist + return repo.commit(text=commitmsg, user=orig.user(), + date=orig.date(), extra=extra) + +def _relocatecommitinmem(repo, orig, dest, pctx, keepbranch, commitmsg, extra): + """rewrites the orig rev on dest rev in memory + + Creates the new commit by using the modern way of creating + commits without writing files to the working copy. + + returns the node of new commit which is formed + """ + wctx = context.overlayworkingctx(repo) + wctx.setbase(dest) - targetphase = max(orig.phase(), phases.draft) - configoverride = repo.ui.configoverride({ - (b'phases', b'new-commit'): targetphase - }, source=b'evolve') - with configoverride: - # Commit might fail if unresolved files exist - return repo.commit(text=commitmsg, user=orig.user(), - date=orig.date(), extra=extra) + stats = merge.graft( + repo, + orig, + pctx, + [b'destination', b'evolving'], + keepparent=True, + wctx=wctx + ) + + if stats.unresolvedcount: # some conflict + raise error.InMemoryMergeConflictsError() + + branch = None + if keepbranch: + branch = orig.branch() + # FIXME: We call _compact() because it's required to correctly detect + # changed files. This was added to fix a regression shortly before the 5.5 + # release. A proper fix will be done in the default branch. + wctx._compact() + memctx = wctx.tomemctx( + commitmsg, + date=orig.date(), + extra=extra, + user=orig.user(), + branch=branch, + ) + if memctx.isempty() and not repo.ui.configbool(b'ui', b'allowemptycommit'): + return None + return repo.commitctx(memctx) def _finalizerelocate(repo, orig, dest, nodenew, tr, category, evolvestate): if nodenew is not None: @@ -1397,8 +1472,20 @@ return opts -def _cleanup(ui, repo, startnode, shouldupdate): - if not shouldupdate: +def _cleanup(ui, repo, startnode, shouldupdate, headnode): + """Update to the right destination after evolving, if necessary + + headnode is the last node created by the evolve operation (which + we may need to update to when using in-memory merge) + """ + # If --update was passed, we should update to some head of the evolved set, + # but we only need to do that in the in-memory case. If --update was not + # passed, we should still update the working copy to its successor if there + # is one. + if shouldupdate: + if use_in_memory_merge(repo) and headnode: + compat.update(repo[headnode]) + else: # Move back to startnode, or to its successor if the start node is # obsolete (perhaps made obsolete by the current `hg evolve`) unfi = repo.unfiltered() @@ -1593,13 +1680,14 @@ ui.setconfig(b'ui', b'forcemerge', opts.get('tool', r''), b'evolve') + headnode = None evolvestate = state.cmdstate(repo) # Continuation handling if contopt: if not evolvestate: raise error.Abort(_(b'no interrupted evolve to continue')) evolvestate.load() - continueevolve(ui, repo, evolvestate) + headnode = continueevolve(ui, repo, evolvestate) if evolvestate[b'command'] != b'evolve': evolvestate.delete() return @@ -1612,8 +1700,11 @@ raise error.Abort(_(b'no interrupted evolve to stop')) evolvestate.load() stopevolve(ui, repo, evolvestate) + if evolvestate[b'command'] != b'evolve': + evolvestate.delete() + return + startnode = repo.unfiltered()[evolvestate[b'startnode']] evolvestate.delete() - return elif abortopt: if not evolvestate: raise error.Abort(_(b'no interrupted evolve to abort')) @@ -1624,7 +1715,7 @@ compat.clean_update(pctx) ui.status(_(b'evolve aborted\n')) ui.status(_(b'working directory is now at %s\n') - % pctx.hex()[:12]) + % pctx) evolvestate.delete() return 0 return abortevolve(ui, repo, evolvestate) @@ -1672,21 +1763,26 @@ tr = repo.transaction(b"evolve") with util.acceptintervention(tr): for rev in revs: - _solveonerev(ui, repo, rev, evolvestate, activetopic, dryrunopt, - confirmopt, progresscb, targetcat) + (solved, newnode) = _solveonerev(ui, repo, rev, evolvestate, + activetopic, dryrunopt, + confirmopt, progresscb, + targetcat) + if solved: + headnode = newnode seen += 1 if showprogress: compat.progress(ui, _(b'evolve'), None) - _cleanup(ui, repo, startnode, shouldupdate) + _cleanup(ui, repo, startnode, shouldupdate, headnode) def _solveonerev(ui, repo, rev, evolvestate, activetopic, dryrunopt, confirmopt, progresscb, targetcat): """solves one trouble, including orphan merges Like _solveone(), this solves one trouble. Unlike _solveone(), it - stabilizes for both parents of orphan merges. + stabilizes for both parents of orphan merges. Returns the same value as + _solveone(). """ curctx = repo[rev] revtopic = getattr(curctx, 'topic', lambda: b'')() @@ -1719,6 +1815,7 @@ evolvestate[b'skippedrevs'].append(curctx.node()) evolvestate[b'orphanmerge'] = False + return ret def solveobswdp(ui, repo, opts): """this function updates to the successor of obsolete wdir parent""" @@ -1787,7 +1884,6 @@ pctx = repo[b'.'] compat.clean_update(pctx) ui.status(_(b'stopped the interrupted evolve\n')) - ui.status(_(b'working directory is now at %s\n') % pctx) def abortevolve(ui, repo, evolvestate): """ logic for handling of `hg evolve --abort`""" @@ -1862,7 +1958,7 @@ evolvestate.delete() ui.status(_(b'evolve aborted\n')) ui.status(_(b'working directory is now at %s\n') - % nodemod.hex(startnode)[:12]) + % nodemod.short(startnode)) else: raise error.Abort(_(b"unable to abort interrupted evolve, use 'hg " b"evolve --stop' to stop evolve")) @@ -1877,7 +1973,7 @@ compat.clean_update(pctx) ui.status(_(b'evolve aborted\n')) ui.status(_(b'working directory is now at %s\n') - % pctx.hex()[:12]) + % pctx) evolvestate.delete() return 0 return abortevolve(ui, repo, evolvestate) @@ -1911,6 +2007,7 @@ compat.progress(ui, _(b'evolve'), seen, unit=_(b'changesets'), total=count) + headnode = None category = evolvestate[b'category'] confirm = evolvestate[b'confirm'] unfi = repo.unfiltered() @@ -1937,9 +2034,11 @@ if newnode[0]: evolvestate[b'replacements'][curctx.node()] = newnode[1] evolvestate[b'lastsolved'] = newnode[1] + headnode = newnode[1] else: evolvestate[b'skippedrevs'].append(curctx.node()) seen += 1 + return headnode def _continuecontentdivergent(ui, repo, evolvestate, progresscb): """function to continue the interrupted content-divergence resolution.""" diff -r 785b5be835ee -r d161fccccd80 hgext3rd/evolve/metadata.py --- a/hgext3rd/evolve/metadata.py Sun Jan 31 15:57:57 2021 +0800 +++ b/hgext3rd/evolve/metadata.py Thu Mar 11 14:32:26 2021 +0800 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -__version__ = b'10.2.0.dev' -testedwith = b'4.6.2 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6' +__version__ = b'10.3.0.dev' +testedwith = b'4.6.2 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7' minimumhgversion = b'4.6' buglink = b'https://bz.mercurial-scm.org/' diff -r 785b5be835ee -r d161fccccd80 hgext3rd/evolve/obshistory.py --- a/hgext3rd/evolve/obshistory.py Sun Jan 31 15:57:57 2021 +0800 +++ b/hgext3rd/evolve/obshistory.py Thu Mar 11 14:32:26 2021 +0800 @@ -61,7 +61,7 @@ (b'f', b'filternonlocal', False, _(b'filter out non local commits')), (b'o', b'origin', True, _(b'show origin of changesets instead of fate')), ] + commands.formatteropts, - _(b'hg olog [OPTION]... [[-r] REV]...'), + _(b'hg obslog [OPTION]... [[-r] REV]...'), **compat.helpcategorykwargs('CATEGORY_CHANGE_NAVIGATION')) def cmdobshistory(ui, repo, *revs, **opts): """show the obsolescence history of the specified revisions diff -r 785b5be835ee -r d161fccccd80 hgext3rd/evolve/revset.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext3rd/evolve/revset.py Thu Mar 11 14:32:26 2021 +0800 @@ -0,0 +1,188 @@ +from __future__ import absolute_import + +from mercurial import ( + node as nodemod, + obsolete, + revset, +) + +from . import ( + compat, + exthelper, + rewind, +) + +eh = exthelper.exthelper() + +##################################################################### +### experimental behavior ### +##################################################################### + +getrevs = obsolete.getrevs + +### Unstable revset symbol + +# hg <= 5.3 (48b99af7b4b3) +@eh.revsetpredicate(b'unstable()') +def revsetunstable(repo, subset, x): + """Changesets with instabilities. + """ + revset.getargs(x, 0, 0, b'unstable takes no arguments') + troubled = set() + troubled.update(getrevs(repo, b'orphan')) + troubled.update(getrevs(repo, b'phasedivergent')) + troubled.update(getrevs(repo, b'contentdivergent')) + troubled = revset.baseset(troubled) + troubled.sort() # set is non-ordered, enforce order + return subset & troubled + +@eh.revsetpredicate(b'troubled()') # legacy name +def revsettroubled(repo, subset, x): + return revsetunstable(repo, subset, x) + +### Obsolescence graph + +# XXX SOME MAJOR CLEAN UP TO DO HERE XXX + +def _precursors(repo, s, includeidentical=False): + """Precursor of a changeset""" + cs = set() + getrev = compat.getgetrev(repo.changelog) + markerbysubj = repo.obsstore.predecessors + node = repo.changelog.node + for r in s: + for p in markerbysubj.get(node(r), ()): + if not includeidentical and p[2] & rewind.identicalflag: + continue + pr = getrev(p[0]) + if pr is not None: + cs.add(pr) + cs -= repo.changelog.filteredrevs # nodemap has no filtering + return cs + +def _allprecursors(repo, s): # XXX we need a better naming + """transitive precursors of a subset""" + node = repo.changelog.node + toproceed = [node(r) for r in s] + seen = set() + allsubjects = repo.obsstore.predecessors + while toproceed: + nc = toproceed.pop() + for mark in allsubjects.get(nc, ()): + np = mark[0] + if np not in seen: + seen.add(np) + toproceed.append(np) + getrev = compat.getgetrev(repo.changelog) + cs = set() + for p in seen: + pr = getrev(p) + if pr is not None: + cs.add(pr) + cs -= repo.changelog.filteredrevs # nodemap has no filtering + return cs + +def _successors(repo, s): + """Successors of a changeset""" + cs = set() + node = repo.changelog.node + getrev = compat.getgetrev(repo.changelog) + markerbyobj = repo.obsstore.successors + for r in s: + for p in markerbyobj.get(node(r), ()): + for sub in p[1]: + sr = getrev(sub) + if sr is not None: + cs.add(sr) + cs -= repo.changelog.filteredrevs # nodemap has no filtering + return cs + +def _allsuccessors(repo, s, haltonflags=0): # XXX we need a better naming + """transitive successors of a subset + + haltonflags allows to provide flags which prevent the evaluation of a + marker. """ + node = repo.changelog.node + toproceed = [node(r) for r in s] + seen = set() + allobjects = repo.obsstore.successors + while toproceed: + nc = toproceed.pop() + for mark in allobjects.get(nc, ()): + if mark[2] & haltonflags: + continue + for sub in mark[1]: + if sub == nodemod.nullid: + continue # should not be here! + if sub not in seen: + seen.add(sub) + toproceed.append(sub) + getrev = compat.getgetrev(repo.changelog) + cs = set() + for s in seen: + sr = getrev(s) + if sr is not None: + cs.add(sr) + cs -= repo.changelog.filteredrevs # nodemap has no filtering + return cs + +##################################################################### +### Extending revsets ### +##################################################################### + +# this section adds several useful revset predicates not yet in core. +# they are subject to changes + +### XXX I'm not sure this revset is useful +@eh.revsetpredicate(b'suspended()') +def revsetsuspended(repo, subset, x): + """Obsolete changesets with non-obsolete descendants. + """ + revset.getargs(x, 0, 0, b'suspended takes no arguments') + suspended = revset.baseset(getrevs(repo, b'suspended')) + suspended.sort() + return subset & suspended + +@eh.revsetpredicate(b'predecessors(set)') +def revsetpredecessors(repo, subset, x): + """Immediate predecessors of changesets in set. + """ + s = revset.getset(repo, revset.fullreposet(repo), x) + s = revset.baseset(_precursors(repo, s)) + s.sort() + return subset & s + +@eh.revsetpredicate(b'precursors(set)') # legacy name for predecessors +def revsetprecursors(repo, subset, x): + return revsetpredecessors(repo, subset, x) + +@eh.revsetpredicate(b'allpredecessors(set)') +def revsetallpredecessors(repo, subset, x): + """Transitive predecessors of changesets in set. + """ + s = revset.getset(repo, revset.fullreposet(repo), x) + s = revset.baseset(_allprecursors(repo, s)) + s.sort() + return subset & s + +@eh.revsetpredicate(b'allprecursors(set)') # legacy name for allpredecessors +def revsetallprecursors(repo, subset, x): + return revsetallpredecessors(repo, subset, x) + +@eh.revsetpredicate(b'successors(set)') +def revsetsuccessors(repo, subset, x): + """Immediate successors of changesets in set. + """ + s = revset.getset(repo, revset.fullreposet(repo), x) + s = revset.baseset(_successors(repo, s)) + s.sort() + return subset & s + +@eh.revsetpredicate(b'allsuccessors(set)') +def revsetallsuccessors(repo, subset, x): + """Transitive successors of changesets in set. + """ + s = revset.getset(repo, revset.fullreposet(repo), x) + s = revset.baseset(_allsuccessors(repo, s)) + s.sort() + return subset & s diff -r 785b5be835ee -r d161fccccd80 hgext3rd/evolve/rewind.py --- a/hgext3rd/evolve/rewind.py Sun Jan 31 15:57:57 2021 +0800 +++ b/hgext3rd/evolve/rewind.py Thu Mar 11 14:32:26 2021 +0800 @@ -20,6 +20,7 @@ from . import ( compat, exthelper, + obshistory, rewriteutil, ) @@ -93,6 +94,9 @@ targets = _select_rewind_targets(repo, opts) + extratargets = _walk_obsmarkers(ui, unfi, targets) + targets.extend(extratargets) + for rev in targets: ctx = unfi[rev] ssets = obsutil.successorssets(repo, ctx.node(), cache=sscache) @@ -188,6 +192,139 @@ if update_target is not None and not opts.get('keep'): ui.status(_(b'working directory is now at %s\n') % repo[b'.']) +def _check_multiple_predecessors(targetnode, successor, targetset): + """ check if a successor of one rewind target is already another target + + An example obsolescence marker tree: + A0 A1 A2 + x - x - o + + When user tries to rewind A2 to both its predecessors with e.g. + `hg rewind --to A0+A1`, this function will at one point be called with + (A0, A1, [A0, A1]) as arguments. In that case it will raise an Abort + and prevent rewind from succeeding. + """ + if successor in targetset: + msg = _(b'not rewinding, %s is a successor of %s') + msg %= (nodemod.short(successor), nodemod.short(targetnode)) + hint = _(b'pick only one of these changesets, possibly with --exact') + raise error.Abort(msg, hint=hint) + +def _walk_successors(ui, unfi, targetset): + """follow successors of targets and find the latest successors + + While doing that, check and abort if there are multiple unrelated + predecessors in targetset. + + We also keep track of "source": when we reach a successor by following the + obsmarker-graph starting from a certain target, we add `successor: target` + pair to `source`. But we don't care about having more than one `target` + (i.e. predecessor) for each `successor`, because `source` is used later on + for finding "new" successors that we didn't find in this function. + """ + source = {} + latest = set() + for targetnode in targetset: + # following successors for each target node separately + remaining = set([targetnode]) + while remaining: + current = remaining.pop() + markers = unfi.obsstore.successors.get(current, ()) + for marker in markers: + for successor in marker[1]: + if successor in source: + # We have already reached this successor while + # processing this or any other targetnode. This means + # not every target node will get their latest successor + # found if e.g. there's a fold (and that is fine). + # (Also basic cycle protection.) + continue + # TODO: this could be moved to a post-processing stage + _check_multiple_predecessors(targetnode, successor, targetset) + source[successor] = current + remaining.add(successor) + if not markers: + latest.add(current) + + return latest, source + +def _check_unknown_predecessors(unfi, nodes, source): + """ check if any nodes are absent from both source and unfiltered repo + + If node is not in source, we might want it as an extra rewind target. But + if it's also absent from local (unfiltered) repo, we need to warn user and + abort. + """ + missing = { + node for node in nodes + if node not in source and node not in unfi + } + if missing: + msg = _(b'not rewinding, some predecessors are unknown locally: %s') + msg %= b' '.join(nodemod.short(m) for m in missing) + hint = _(b'try selecting all changesets to rewind to manually, ' + b'possibly with --exact') + raise error.Abort(msg, hint=hint) + +def _walk_predecessors(ui, unfi, targetset, latest, source): + """follow predecessors of targets, validate and suggest extra targets + + While doing that, check and abort if any fold components are unknown. + + Skip predecessors that are only reachable by following obsmarkers with + "identical" flag, because these markers are for internal use and actual + users don't want to revive such predecessors. + + Note: picking the first reached (IOW, the latest) predecessor is done on + purpose. We don't want rewind to assume too much, but also, and more + importantly, we don't want rewind to deal with any potential merge + conflicts. And when rewind revives one of the latest predecessors and it is + based on an obsolete changeset that was not revived, the revived changeset + will simply be an orphan, and it will be up to the user to decide how they + want to solve the trouble _after_ rewind is finished. This way of handling + rewinds that may produce merge conflicts means less chance to lose work. + """ + remaining = set(latest) + seen = set(remaining) + extratargets = [] + while remaining: + successor = remaining.pop() + markers = unfi.obsstore.predecessors.get(successor, ()) + data = (((marker[0],), (marker,)) for marker in markers) + for (nodes, markers) in sorted(obshistory.groupbyfoldid(data)): + # TODO: this could be moved to a post-processing stage + _check_unknown_predecessors(unfi, nodes, source) + for node in nodes: + if node in seen: + # basic cycle protection + continue + if node in source: + # we've been here while following successors + seen.add(node) + remaining.add(node) + elif node not in targetset: + # skipping meta obsmarkers from previous rewind operations + identical = [m[2] & identicalflag for m in markers] + if not all(identical): + extratargets.append(unfi[node].rev()) + + return extratargets + +def _walk_obsmarkers(ui, unfi, targets): + """walking of both successors and predecessors of changesets to rewind to + + This function: + - traverses successors of every target, then + - traverses predecessors of every latest successor of each target + - returns reachable predecessors with content changes + """ + node = unfi.changelog.node + targetset = set(node(target) for target in targets) + latest, source = _walk_successors(ui, unfi, targetset) + extratargets = _walk_predecessors(ui, unfi, targetset, latest, source) + + return extratargets + def _select_rewind_targets(repo, opts): """select the revisions we should rewind to """ diff -r 785b5be835ee -r d161fccccd80 hgext3rd/topic/__init__.py --- a/hgext3rd/topic/__init__.py Sun Jan 31 15:57:57 2021 +0800 +++ b/hgext3rd/topic/__init__.py Thu Mar 11 14:32:26 2021 +0800 @@ -4,7 +4,7 @@ # GNU General Public License version 2 or any later version. """support for topic branches -Topic branches are lightweight branches which disappear when changes are +Topic branches are lightweight branches which fade out when changes are finalized (move to the public phase). Compared to bookmark, topic is reference carried by each changesets of the @@ -232,9 +232,9 @@ b'topic.active': b'green', } -__version__ = b'0.21.0.dev' +__version__ = b'0.22.0.dev' -testedwith = b'4.6.2 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6' +testedwith = b'4.6.2 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7' minimumhgversion = b'4.6' buglink = b'https://bz.mercurial-scm.org/' diff -r 785b5be835ee -r d161fccccd80 tests/test-check-sdist.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-check-sdist.t Thu Mar 11 14:32:26 2021 +0800 @@ -0,0 +1,60 @@ +Enable obsolescence to avoid the warning issue when obsmarkers are found + + $ cat << EOF >> "$HGRCPATH" + > [experimental] + > evolution = all + > EOF + + $ cd "$TESTDIR"/.. + +Archiving to a separate location to avoid hardlink mess when the repo is shared + +#if test-repo + + $ hg archive "$TESTTMP"/hg-evolve + $ cd "$TESTTMP"/hg-evolve + +#endif + + $ "$PYTHON" setup.py sdist --dist-dir "$TESTTMP"/dist > /dev/null + */dist.py:*: UserWarning: Unknown distribution option: 'python_requires' (glob) + warnings.warn(msg) + warning: sdist: standard file not found: should have one of README, README.txt (?) + (?) + warning: no previously-included files found matching 'docs/tutorial/.netlify' + warning: no previously-included files found matching '.gitlab-ci.yml' + warning: no previously-included files found matching '.hg-format-source' + warning: no previously-included files found matching 'Makefile' + no previously-included directories found matching 'contrib' + no previously-included directories found matching 'debian' + no previously-included directories found matching '.gitlab' + $ cd "$TESTTMP"/dist + + $ wc -c hg-evolve-*.tar.gz + 8????? hg-evolve-*.tar.gz (glob) + + $ tar -tzf hg-evolve-*.tar.gz | sed 's|^hg-evolve-[^/]*/||' | sort > files + $ wc -l files + 346 files + $ fgrep debian files + tests/test-check-debian.t + $ fgrep __init__.py files + hgext3rd/__init__.py + hgext3rd/evolve/__init__.py + hgext3rd/evolve/thirdparty/__init__.py + hgext3rd/topic/__init__.py + $ fgrep common.sh files + docs/tutorial/testlib/common.sh + tests/testlib/common.sh + $ fgrep README files + README.rst + docs/README + docs/tutorial/README.rst + hgext3rd/topic/README + + $ egrep '(gitlab|contrib|hack|format-source)' files + [1] + $ fgrep legacy.py files + [1] + $ fgrep netlify files + [1] diff -r 785b5be835ee -r d161fccccd80 tests/test-corrupt.t --- a/tests/test-corrupt.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-corrupt.t Thu Mar 11 14:32:26 2021 +0800 @@ -1,17 +1,9 @@ $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * > [phases] > publish = False > [alias] > qlog = log --template='{rev} - {node|short} {desc} ({phase})\n' - > [diff] - > git = 1 - > unified = 0 > [extensions] > EOF $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-abort-orphan.t diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-abort-phasediv.t --- a/tests/test-evolve-abort-phasediv.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-abort-phasediv.t Thu Mar 11 14:32:26 2021 +0800 @@ -24,6 +24,14 @@ > abort = evolve --abort > EOF +#testcases inmemory ondisk +#if inmemory + $ cat >> $HGRCPATH < [experimental] + > evolution.in-memory = yes + > EOF +#endif + $ hg init abortrepo $ cd abortrepo $ echo ".*\.orig" > .hgignore diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-content-divergent-basic.t --- a/tests/test-evolve-content-divergent-basic.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-content-divergent-basic.t Thu Mar 11 14:32:26 2021 +0800 @@ -8,14 +8,6 @@ $ cat >> $HGRCPATH < [alias] > glog = log -GT "{rev}:{node|short} {desc|firstline}\n ({bookmarks}) [{branch}] {phase}" - > [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish = False > [diff] > git = 1 > unified = 0 diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-content-divergent-case-A5.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-evolve-content-divergent-case-A5.t Thu Mar 11 14:32:26 2021 +0800 @@ -0,0 +1,183 @@ +=============================================== +Testing content-divergence resolution: Case A.5 +=============================================== + +Independent rewrites of same changeset can lead to content-divergence. In most +common cases, it can occur when multiple users rewrite the same changeset +independently and push it. + +This test belongs to a series of tests checking the resolution of content-divergent +changesets. + +Category A: no parents are obsolete +Testcase 5: one side relocated backward and other rebased to parent's successor +Variants: +# a: "local" is relocated backward +# b: "other" is relocated backward + +A.5 Relocated backward; Rebased to parent's successor +===================================================== + +.. (Divergence reason): +.. local: relocated the changeset backward in the graph +.. other: rebased to the successor of parent +.. Since one side rebased to the successor of parent and other cset relocated backward, +.. the most reasonable behaviour is to set the parent of "backward-relocated" cset +.. as resolution parent of divergence. +.. +.. (local): +.. +.. C ø⇠○ C' +.. | | +.. B ○ | +.. | / +.. A ○ +.. | +.. O ● +.. +.. (other): +.. +.. C ø⇠○ C'' +.. | | +.. B ø⇠○ B' +.. | / +.. A ○ +.. | +.. O ● +.. +.. (Resolution): +.. +.. B'○ ○ C''' +.. | / +.. A ○ +.. | +.. O ● +.. + +Setup +----- + $ . $TESTDIR/testlib/content-divergence-util.sh + $ setuprepos A.5 + creating test repo for test case A.5 + - upstream + - local + - other + cd into `local` and proceed with env setup + +initial + + $ cd upstream + $ mkcommit A + $ mkcommit B + $ mkcommit C + $ cd ../local + $ hg pull -qu + $ hg rebase -r 'desc(C)' -d 'desc(A)' + rebasing 3:d90aa47aa5d3 "C" (tip) + + $ cd ../other + $ hg pull -qu + $ hg prev + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + [2] B + $ echo newB > B + $ hg amend + 1 new orphan changesets + $ hg next + move:[3] C + atop:[4] B + working directory is now at f085ae420789 + $ hg push -q + + $ cd ../local + $ hg push -fq + 2 new content-divergent changesets + $ hg pull -q + 2 new content-divergent changesets + + +Actual test of resolution +------------------------- + +Variant_a: when "local" is rebased backward +------------------------------------------- + $ hg evolve -l + b80b2bbeb664: C + content-divergent: f085ae420789 (draft) (precursor d90aa47aa5d3) + + f085ae420789: C + content-divergent: b80b2bbeb664 (draft) (precursor d90aa47aa5d3) + + $ hg log -G + * 6:f085ae420789 (draft): C [content-divergent] + | + o 5:7db72af2e30d (draft): B + | + | @ 4:b80b2bbeb664 (draft): C [content-divergent] + |/ + o 1:f5bc6836db60 (draft): A + | + o 0:a9bdc8b26820 (public): O + + $ hg evolve --content-divergent + merge:[4] C + with: [6] C + base: [3] C + rebasing "other" content-divergent changeset f085ae420789 on f5bc6836db60 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + working directory is now at 88b737dc9dd8 + + $ hg log -G + @ 8:88b737dc9dd8 (draft): C + | + | o 5:7db72af2e30d (draft): B + |/ + o 1:f5bc6836db60 (draft): A + | + o 0:a9bdc8b26820 (public): O + + $ hg evolve -l + + +Variant_b: when "other" is rebased backward +------------------------------------------- + + $ cd ../other + $ hg pull -q + 2 new content-divergent changesets + $ hg evolve -l + f085ae420789: C + content-divergent: b80b2bbeb664 (draft) (precursor d90aa47aa5d3) + + b80b2bbeb664: C + content-divergent: f085ae420789 (draft) (precursor d90aa47aa5d3) + + $ hg log -G + * 6:b80b2bbeb664 (draft): C [content-divergent] + | + | @ 5:f085ae420789 (draft): C [content-divergent] + | | + | o 4:7db72af2e30d (draft): B + |/ + o 1:f5bc6836db60 (draft): A + | + o 0:a9bdc8b26820 (public): O + + $ hg evolve --content-divergent + merge:[5] C + with: [6] C + base: [3] C + rebasing "divergent" content-divergent changeset f085ae420789 on f5bc6836db60 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + working directory is now at fa4ff8bb3531 + + $ hg log -G + @ 8:fa4ff8bb3531 (draft): C + | + | o 4:7db72af2e30d (draft): B + |/ + o 1:f5bc6836db60 (draft): A + | + o 0:a9bdc8b26820 (public): O + + $ hg evolve -l diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-content-divergent-case-B1.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-evolve-content-divergent-case-B1.t Thu Mar 11 14:32:26 2021 +0800 @@ -0,0 +1,198 @@ +=============================================== +Testing content-divergence resolution: Case B.1 +=============================================== + +Independent rewrites of same changeset can lead to content-divergence. In most +common cases, it can occur when multiple users rewrite the same changeset +independently and push it. + +This test belongs to a series of tests checking the resolution of content-divergent +changesets. + +Category B: parents are obsolete +Testcase 1: one side amended changes and other rebased to in-between successor of basep1 +Variants: +# a: default resolution +# b: minimal resolution using `experimental.evolution.divergence-resolution-minimal=True` + +B.1 Relocated backward; Rebased to parent's successor +===================================================== + +.. (Divergence reason): +.. local: rebased to the 'in-between' successor of basep1 +.. other: amended some changes +.. The default resolution here is that we choose the final successor as resolution parent, +.. but this behavior can be changed to use the 'in-between' successor as resolution parent +.. by using a config option `experimental.evolution.divergence-resolution-minimal=True` +.. +.. This test case is considered complicated and can change its behavior acc. to the user +.. feedback. For more, please look at section 'D-A3.1' in troubles-handling.rst +.. +.. (local): +.. +.. B ø → ○ B' +.. | | +.. A ø → ø A' → ○ A'' +.. | | | +.. |---- | +.. |----------- +.. | +.. O ● +.. +.. (other): +.. +.. B ø→○ B' +.. | / +.. A ○ +.. | +.. O ● +.. +.. (Resolution): +.. +.. ○ B''' +.. | +.. ○ A'' +.. | +.. ● O +.. + +Setup +----- + $ . $TESTDIR/testlib/content-divergence-util.sh + $ setuprepos B.1 + creating test repo for test case B.1 + - upstream + - local + - other + cd into `local` and proceed with env setup + +initial + + $ cd upstream + $ mkcommit A + $ mkcommit B + $ cd ../local + $ hg pull -qu + $ hg prev + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + [1] A + $ echo fooA >> A + $ hg amend -m 'new_A' + 1 new orphan changesets + $ hg evolve + move:[2] B + atop:[3] new_A + $ echo barA >> A + $ hg amend -m 'latest_A' + 1 new orphan changesets + + $ cd ../other + $ hg pull -qu + $ echo fooB > B + $ hg amend -m 'new_B' + $ hg push -q + + $ cd ../local + $ hg push -fq + 2 new orphan changesets + 2 new content-divergent changesets + $ hg pull -q + 1 new orphan changesets + 2 new content-divergent changesets + + +Actual test of resolution +------------------------- + +Variant_a: default resolution +----------------------------- + $ hg evolve -l + 429afd16ac76: B + orphan: 1ffcccee011c (obsolete parent) + content-divergent: 807cc2b37fb3 (draft) (precursor f6fbb35d8ac9) + + 807cc2b37fb3: new_B + orphan: f5bc6836db60 (obsolete parent) + content-divergent: 429afd16ac76 (draft) (precursor f6fbb35d8ac9) + + $ hg log -G + * 6:807cc2b37fb3 (draft): new_B [orphan content-divergent] + | + | @ 5:45ed635c7cfc (draft): latest_A + | | + | | * 4:429afd16ac76 (draft): B [orphan content-divergent] + | | | + | | x 3:1ffcccee011c (draft): new_A + | |/ + x | 1:f5bc6836db60 (draft): A + |/ + o 0:a9bdc8b26820 (public): O + + $ hg evolve --content-divergent + merge:[4] B + with: [6] new_B + base: [2] B + rebasing "divergent" content-divergent changeset 429afd16ac76 on 45ed635c7cfc + rebasing "other" content-divergent changeset 807cc2b37fb3 on 45ed635c7cfc + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ hg log -G + o 9:6f740085e668 (draft): new_B + | + @ 5:45ed635c7cfc (draft): latest_A + | + o 0:a9bdc8b26820 (public): O + + $ hg evolve -l + + +Variant_b: minimal resolution +----------------------------- + + $ cd ../other + $ hg pull -q + 2 new orphan changesets + 2 new content-divergent changesets + $ hg evolve -l + 807cc2b37fb3: new_B + orphan: f5bc6836db60 (obsolete parent) + content-divergent: 429afd16ac76 (draft) (precursor f6fbb35d8ac9) + + 429afd16ac76: B + orphan: 1ffcccee011c (obsolete parent) + content-divergent: 807cc2b37fb3 (draft) (precursor f6fbb35d8ac9) + + $ hg log -G + o 6:45ed635c7cfc (draft): latest_A + | + | * 5:429afd16ac76 (draft): B [orphan content-divergent] + | | + | x 4:1ffcccee011c (draft): new_A + |/ + | @ 3:807cc2b37fb3 (draft): new_B [orphan content-divergent] + | | + | x 1:f5bc6836db60 (draft): A + |/ + o 0:a9bdc8b26820 (public): O + + $ hg evolve --content-divergent --config experimental.evolution.divergence-resolution-minimal=True + merge:[3] new_B + with: [5] B + base: [2] B + rebasing "divergent" content-divergent changeset 807cc2b37fb3 on 1ffcccee011c + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + working directory is now at 2431e876af63 + + $ hg log -G + @ 8:2431e876af63 (draft): new_B [orphan] + | + | o 6:45ed635c7cfc (draft): latest_A + | | + x | 4:1ffcccee011c (draft): new_A + |/ + o 0:a9bdc8b26820 (public): O + + $ hg evolve -l + 2431e876af63: new_B + orphan: 1ffcccee011c (obsolete parent) + diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-content-divergent-corner-cases.t --- a/tests/test-evolve-content-divergent-corner-cases.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-content-divergent-corner-cases.t Thu Mar 11 14:32:26 2021 +0800 @@ -8,14 +8,6 @@ $ cat >> $HGRCPATH < [alias] > glog = log -GT "{rev}:{node|short} {desc|firstline}\n ({bookmarks}) [{branch}] {phase}" - > [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish = False > [diff] > git = 1 > unified = 0 diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-content-divergent-interrupted.t --- a/tests/test-evolve-content-divergent-interrupted.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-content-divergent-interrupted.t Thu Mar 11 14:32:26 2021 +0800 @@ -259,12 +259,10 @@ $ echo ".*\.orig" > .hgignore $ hg add .hgignore $ hg ci -m "added hgignore" - $ for ch in a b c d; do echo foo > $ch; hg add $ch; hg ci -qm "added "$ch; done; + $ for ch in a b c; do echo foo > $ch; hg add $ch; hg ci -qm "added "$ch; done; $ hg glog - @ 4:c41c793e0ef1 added d - | () draft - o 3:ca1b80f7960a added c + @ 3:ca1b80f7960a added c | () draft o 2:b1661037fa25 added b | () draft @@ -273,28 +271,36 @@ o 0:8fa14d15e168 added hgignore () draft +changes to get merge conflict during relocation + $ echo "some_changes" >> a + $ hg amend + $ echo foo > d + $ hg add d + $ hg ci -m "added d" + $ hg rebase -r . -d .^^^ --config extensions.rebase= - rebasing 4:c41c793e0ef1 "added d" (tip) + rebasing 5:f8b09dd867e5 "added d" (tip) $ echo bar > c $ hg add c $ hg amend $ hg up --hidden 'min(desc("added d"))' - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved - updated to hidden changeset c41c793e0ef1 - (hidden revision 'c41c793e0ef1' was rewritten as: 69bdd23a9b0d) - working directory parent is obsolete! (c41c793e0ef1) - (use 'hg evolve' to update to its successor: 69bdd23a9b0d) + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + updated to hidden changeset f8b09dd867e5 + (hidden revision 'f8b09dd867e5' was rewritten as: 6f7eaf1944c0) + working directory parent is obsolete! (f8b09dd867e5) + (use 'hg evolve' to update to its successor: 6f7eaf1944c0) $ echo bar > d + $ echo "latest_changes" >> a $ hg amend 2 new content-divergent changesets $ hg glog - @ 7:e49523854bc8 added d + @ 8:a8673909e314 added d | () draft - | * 6:69bdd23a9b0d added d + | * 7:6f7eaf1944c0 added d | | () draft - o | 3:ca1b80f7960a added c + o | 4:33c16a2e0eb8 added c | | () draft o | 2:b1661037fa25 added b |/ () draft @@ -304,28 +310,26 @@ () draft $ hg evolve --content-divergent - merge:[6] added d - with: [7] added d - base: [4] added d - rebasing "other" content-divergent changeset e49523854bc8 on c7586e2a9264 - file 'c' was deleted in other but was modified in local. - What do you want to do? - use (c)hanged version, (d)elete, or leave (u)nresolved? u - 1 files updated, 0 files merged, 0 files removed, 1 files unresolved + merge:[7] added d + with: [8] added d + base: [5] added d + rebasing "other" content-divergent changeset a8673909e314 on c7586e2a9264 + merging a + warning: conflicts while merging a! (edit, then use 'hg resolve --mark') unresolved merge conflicts (see 'hg help evolve.interrupted') [1] $ hg evolve --abort evolve aborted - working directory is now at e49523854bc8 + working directory is now at a8673909e314 $ hg glog - @ 7:e49523854bc8 added d + @ 8:a8673909e314 added d | () draft - | * 6:69bdd23a9b0d added d + | * 7:6f7eaf1944c0 added d | | () draft - o | 3:ca1b80f7960a added c + o | 4:33c16a2e0eb8 added c | | () draft o | 2:b1661037fa25 added b |/ () draft @@ -339,17 +343,17 @@ --------------------------------------------------------------------------------- $ hg up 'min(desc("added d"))' - 2 files updated, 0 files merged, 1 files removed, 0 files unresolved + 3 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg rm c $ echo wat > d $ hg amend $ hg glog - @ 8:33e4442acf98 added d + @ 9:b6a3f3ee0c44 added d | () draft - | * 7:e49523854bc8 added d + | * 8:a8673909e314 added d | | () draft - | o 3:ca1b80f7960a added c + | o 4:33c16a2e0eb8 added c | | () draft | o 2:b1661037fa25 added b |/ () draft @@ -359,27 +363,44 @@ () draft $ hg evolve --content-divergent - merge:[7] added d - with: [8] added d - base: [4] added d - rebasing "divergent" content-divergent changeset e49523854bc8 on c7586e2a9264 + merge:[8] added d + with: [9] added d + base: [5] added d + rebasing "divergent" content-divergent changeset a8673909e314 on c7586e2a9264 + merging a + warning: conflicts while merging a! (edit, then use 'hg resolve --mark') + unresolved merge conflicts + (see 'hg help evolve.interrupted') + [1] + +this test case is mainly to test that we hit merge conlict while merging the +two divergent csets, so resolving this one which happened during relocation + $ echo a > a + $ hg res -m + (no more unresolved files) + continue: hg evolve --continue + + $ hg evolve -c + evolving 8:a8673909e314 "added d" + merging a merging d + warning: conflicts while merging a! (edit, then use 'hg resolve --mark') warning: conflicts while merging d! (edit, then use 'hg resolve --mark') - 0 files updated, 0 files merged, 0 files removed, 1 files unresolved + 0 files updated, 0 files merged, 0 files removed, 2 files unresolved unresolved merge conflicts (see 'hg help evolve.interrupted') [1] $ hg evolve --abort evolve aborted - working directory is now at 33e4442acf98 + working directory is now at b6a3f3ee0c44 $ hg glog - @ 8:33e4442acf98 added d + @ 9:b6a3f3ee0c44 added d | () draft - | * 7:e49523854bc8 added d + | * 8:a8673909e314 added d | | () draft - | o 3:ca1b80f7960a added c + | o 4:33c16a2e0eb8 added c | | () draft | o 2:b1661037fa25 added b |/ () draft @@ -517,12 +538,12 @@ $ hg evolve --stop stopped the interrupted evolve - working directory is now at e49523854bc8 + working directory is now at 517d4375cb72 $ hg glog - * 7:517d4375cb72 added d + @ 7:517d4375cb72 added d | () draft - | @ 5:e49523854bc8 added d + | * 5:e49523854bc8 added d | | () draft | o 3:ca1b80f7960a added c | | () draft @@ -537,17 +558,25 @@ relocation --------------------------------------------------------------------------- - $ echo babar > c - $ hg add c - c already tracked! +Making changes to make sure that it hits conflict while relocating + $ hg up -r 3 + 2 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo "some_changes" >> a + $ hg amend + 1 new orphan changesets + $ hg next + move:[5] added d + atop:[8] added c + working directory is now at dc9ba677cba1 + $ echo "latest_changes" >> a $ hg amend $ hg glog - @ 8:2d664a4ab749 added d + @ 10:0892835a581f added d + | () draft + o 8:33c16a2e0eb8 added c | () draft | * 7:517d4375cb72 added d | | () draft - o | 3:ca1b80f7960a added c - | | () draft o | 2:b1661037fa25 added b |/ () draft o 1:c7586e2a9264 added a @@ -557,47 +586,43 @@ $ hg evolve --content-divergent merge:[7] added d - with: [8] added d + with: [10] added d base: [4] added d - rebasing "other" content-divergent changeset 2d664a4ab749 on c7586e2a9264 - file 'c' was deleted in local but was modified in other. - What do you want to do? - use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u - merging d - warning: conflicts while merging d! (edit, then use 'hg resolve --mark') - 0 files updated, 0 files merged, 0 files removed, 2 files unresolved + rebasing "other" content-divergent changeset 0892835a581f on c7586e2a9264 + merging a + warning: conflicts while merging a! (edit, then use 'hg resolve --mark') unresolved merge conflicts (see 'hg help evolve.interrupted') [1] $ hg diff - diff -r 517d4375cb72 c + diff -r c7586e2a9264 a + --- a/a Thu Jan 01 00:00:00 1970 +0000 + +++ b/a Thu Jan 01 00:00:00 1970 +0000 + @@ -1,1 +1,6 @@ + foo + +<<<<<<< destination: c7586e2a9264 - test: added a + +======= + +some_changes + +latest_changes + +>>>>>>> evolving: 0892835a581f - test: added d + diff -r c7586e2a9264 d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 - +++ b/c Thu Jan 01 00:00:00 1970 +0000 + +++ b/d Thu Jan 01 00:00:00 1970 +0000 @@ -0,0 +1,1 @@ - +babar - diff -r 517d4375cb72 d - --- a/d Thu Jan 01 00:00:00 1970 +0000 - +++ b/d Thu Jan 01 00:00:00 1970 +0000 - @@ -1,1 +1,5 @@ - +<<<<<<< local: 517d4375cb72 - test: added d - foobar - +======= +bar - +>>>>>>> other: e315463d94bd - test: added d $ hg evolve --stop stopped the interrupted evolve - working directory is now at 2d664a4ab749 + working directory is now at 0892835a581f -XXX: we should have preserved the wdir to be at rev 8 $ hg glog - @ 8:2d664a4ab749 added d + @ 10:0892835a581f added d + | () draft + o 8:33c16a2e0eb8 added c | () draft | * 7:517d4375cb72 added d | | () draft - o | 3:ca1b80f7960a added c - | | () draft o | 2:b1661037fa25 added b |/ () draft o 1:c7586e2a9264 added a diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-content-divergent-stack.t --- a/tests/test-evolve-content-divergent-stack.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-content-divergent-stack.t Thu Mar 11 14:32:26 2021 +0800 @@ -749,7 +749,7 @@ $ hg evolve --stop 2 new orphan changesets stopped the interrupted evolve - working directory is now at 2a955e808c53 + working directory is now at 509103439e5e $ hg log -G o changeset: 21:7e67dfb7ee31 | tag: tip @@ -770,7 +770,7 @@ | | instability: orphan, content-divergent | | summary: added c | | - | * changeset: 17:509103439e5e + | @ changeset: 17:509103439e5e | | parent: 5:8e222f257bbf | | user: test | | date: Thu Jan 01 00:00:00 1970 +0000 @@ -789,7 +789,7 @@ | | | instability: orphan, content-divergent | | | summary: added c | | | - | | @ changeset: 14:2a955e808c53 + | | * changeset: 14:2a955e808c53 | | | parent: 10:c04ff147ef79 | | | user: test | | | date: Thu Jan 01 00:00:00 1970 +0000 @@ -837,10 +837,10 @@ x c7586e2a9264 (1) added a $ hg obslog -r 'desc("added b")' --all - @ 2a955e808c53 (14) added b + * 2a955e808c53 (14) added b | amended(content) from 6eb54b5af3fb using amend by test (Thu Jan 01 00:00:00 1970 +0000) | - | * 509103439e5e (17) added b + | @ 509103439e5e (17) added b | | amended(content) from d5f148423c16 using amend by test (Thu Jan 01 00:00:00 1970 +0000) | | x | 6eb54b5af3fb (11) added b diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-continue.t diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-interrupted.t diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-noupdate.t --- a/tests/test-evolve-noupdate.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-noupdate.t Thu Mar 11 14:32:26 2021 +0800 @@ -18,6 +18,14 @@ > EOF $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH +#testcases inmemory ondisk +#if inmemory + $ cat >> $HGRCPATH < [experimental] + > evolution.in-memory = yes + > EOF +#endif + $ hg init stoprepo $ cd stoprepo $ echo ".*\.orig" > .hgignore diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-order.t --- a/tests/test-evolve-order.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-order.t Thu Mar 11 14:32:26 2021 +0800 @@ -2,17 +2,6 @@ ----------------------- $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish = False - > [diff] - > git = 1 - > unified = 0 > [ui] > logtemplate = {rev}:{node|short}@{branch}({phase}) {desc|firstline}\n > [experimental] diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-phase.t diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-serveronly-bundle2.t --- a/tests/test-evolve-serveronly-bundle2.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-serveronly-bundle2.t Thu Mar 11 14:32:26 2021 +0800 @@ -2,8 +2,6 @@ $ . ${TESTDIR}/testlib/pythonpath.sh $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" > [web] > push_ssl = false > allow_push = * diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-serveronly-legacy.t --- a/tests/test-evolve-serveronly-legacy.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-serveronly-legacy.t Thu Mar 11 14:32:26 2021 +0800 @@ -2,8 +2,6 @@ $ . ${TESTDIR}/testlib/pythonpath.sh $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" > [web] > push_ssl = false > allow_push = * diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-split.t --- a/tests/test-evolve-split.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-split.t Thu Mar 11 14:32:26 2021 +0800 @@ -1,17 +1,6 @@ Check that evolve shows error while handling split commits -------------------------------------- $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish = False - > [diff] - > git = 1 - > unified = 0 > [ui] > logtemplate = {rev}:{node|short}@{branch}({phase}) {desc|firstline}\n > [extensions] diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-stop-orphan.t --- a/tests/test-evolve-stop-orphan.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-stop-orphan.t Thu Mar 11 14:32:26 2021 +0800 @@ -153,7 +153,6 @@ $ hg evolve --stop stopped the interrupted evolve - working directory is now at cb6a2ab625bb $ hg glog @ 5:cb6a2ab625bb added c @@ -258,15 +257,15 @@ $ hg evolve --stop stopped the interrupted evolve - working directory is now at aec285328e90 + working directory is now at 21817cd42526 Only changeset which has a successor now are obsoleted $ hg glog - @ 9:aec285328e90 added b + o 9:aec285328e90 added b | () draft o 8:fd00db71edca added a | () draft - o 7:21817cd42526 added hgignore + @ 7:21817cd42526 added hgignore () draft * 6:2a4e03d422e2 added d | () draft @@ -303,11 +302,11 @@ | () draft o 10:cb1dd1086ef6 added c | () draft - @ 9:aec285328e90 added b + o 9:aec285328e90 added b | () draft o 8:fd00db71edca added a | () draft - o 7:21817cd42526 added hgignore + @ 7:21817cd42526 added hgignore () draft Bookmarks should only be moved of the changesets which have been evolved, @@ -315,7 +314,7 @@ ------------------------------------------------------------------------- $ hg up tip^ - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + 4 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg bookmark b1 $ hg up .^ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved @@ -367,13 +366,13 @@ $ hg evolve --stop stopped the interrupted evolve - working directory is now at a3f4b95da934 + working directory is now at a3cc2042492f Bookmarks of only the changeset which are evolved is moved $ hg glog - @ 13:a3f4b95da934 added b + o 13:a3f4b95da934 added b | (b2) draft - o 12:a3cc2042492f added a + @ 12:a3cc2042492f added a | () draft | * 11:cd0909a30222 added d | | () draft diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-stop-phasediv.t --- a/tests/test-evolve-stop-phasediv.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-stop-phasediv.t Thu Mar 11 14:32:26 2021 +0800 @@ -16,6 +16,14 @@ > EOF $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH +#testcases inmemory ondisk +#if inmemory + $ cat >> $HGRCPATH < [experimental] + > evolution.in-memory = yes + > EOF +#endif + $ hg init stoprepo $ cd stoprepo $ echo ".*\.orig" > .hgignore @@ -90,15 +98,14 @@ $ hg evolve --stop stopped the interrupted evolve - working directory is now at ca1b80f7960a + working directory is now at ddba58020bc0 -XXX: maybe we should update wdir to where it was $ hg glog - * 6:ddba58020bc0 added d + @ 6:ddba58020bc0 added d | () draft | o 4:c41c793e0ef1 added d | | () public - | @ 3:ca1b80f7960a added c + | o 3:ca1b80f7960a added c | | () public | o 2:b1661037fa25 added b |/ () public diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-topic.t --- a/tests/test-evolve-topic.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-topic.t Thu Mar 11 14:32:26 2021 +0800 @@ -2,16 +2,8 @@ Check we can find the topic extensions $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > [phases] - > publish = False > [ui] > logtemplate = {rev} - \{{get(namespaces, "topics")}} {node|short} {desc} ({phase})\n - > [diff] - > git = 1 - > unified = 0 > [extensions] > rebase = > EOF diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve-wdir.t --- a/tests/test-evolve-wdir.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve-wdir.t Thu Mar 11 14:32:26 2021 +0800 @@ -35,6 +35,14 @@ > glog = log --graph --template "{rev}:{node|short} ({phase}): {desc|firstline} {if(troubles, '[{troubles}]')}\n" > EOF +#testcases inmemory ondisk +#if inmemory + $ cat >> $HGRCPATH < [experimental] + > evolution.in-memory = yes + > EOF +#endif + $ hg init repo $ cd repo $ mkcommit c_A diff -r 785b5be835ee -r d161fccccd80 tests/test-evolve.t --- a/tests/test-evolve.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-evolve.t Thu Mar 11 14:32:26 2021 +0800 @@ -1,11 +1,4 @@ $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > metaedit=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * > [phases] > publish = False > [alias] @@ -16,6 +9,7 @@ > [extensions] > EOF $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH + $ mkcommit() { > echo "$1" > "$1" > hg add "$1" diff -r 785b5be835ee -r d161fccccd80 tests/test-fold.t --- a/tests/test-fold.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-fold.t Thu Mar 11 14:32:26 2021 +0800 @@ -3,8 +3,6 @@ setup $ cat >> $HGRCPATH < [defaults] - > fold=-d "0 0" > [extensions] > evolve= > [alias] diff -r 785b5be835ee -r d161fccccd80 tests/test-obsolete-push.t --- a/tests/test-obsolete-push.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-obsolete-push.t Thu Mar 11 14:32:26 2021 +0800 @@ -1,6 +1,4 @@ $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" > [extensions] > EOF $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH diff -r 785b5be835ee -r d161fccccd80 tests/test-oldconvert.t --- a/tests/test-oldconvert.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-oldconvert.t Thu Mar 11 14:32:26 2021 +0800 @@ -1,11 +1,4 @@ $ cat >> $HGRCPATH < [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish=False - > [alias] - > odiff=diff --rev 'limit(obsparents(.),1)' --rev . > [extensions] > EOF $ mkcommit() { diff -r 785b5be835ee -r d161fccccd80 tests/test-prev-next.t diff -r 785b5be835ee -r d161fccccd80 tests/test-rewind.t --- a/tests/test-rewind.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-rewind.t Thu Mar 11 14:32:26 2021 +0800 @@ -8,6 +8,7 @@ > publish = false > [alias] > glf = log -GT "{rev}: {desc} ({files})" + > glhf = log -GT "{rev}:{node|short} {desc} ({files})" > [extensions] > evolve = > EOF @@ -663,16 +664,13 @@ rewinding 4535d0af405c to 2 changesets: a0316c4c5417 9576e80d6851 $ hg rewind --to '9576e80d6851' --hidden --dry-run rewinding 4535d0af405c to 2 changesets: a0316c4c5417 9576e80d6851 - -XXX this should also give us 2 changesets - $ hg rewind --to 'a0316c4c5417' --hidden --dry-run - rewinding 4535d0af405c to 1 changesets: a0316c4c5417 + rewinding 4535d0af405c to 2 changesets: a0316c4c5417 9576e80d6851 $ hg rewind --to '9576e80d6851' --exact --hidden --dry-run - rewinding 4535d0af405c to 1 changesets: 9576e80d6851 + rewinding 4535d0af405c to 2 changesets: a0316c4c5417 9576e80d6851 $ hg rewind --to 'a0316c4c5417' --exact --hidden --dry-run - rewinding 4535d0af405c to 1 changesets: a0316c4c5417 + rewinding 4535d0af405c to 2 changesets: a0316c4c5417 9576e80d6851 actual rewind @@ -866,6 +864,19 @@ summary: c_ROOT + $ hg rewind --hidden --to 'allpredecessors(desc("c_B0"))' --dry-run + abort: not rewinding, a65fceb2324a is a successor of 7e594302a05d + (pick only one of these changesets, possibly with --exact) + [255] + $ hg rewind --hidden --to 'allpredecessors(desc("c_B0"))' --dry-run --exact + abort: not rewinding, a65fceb2324a is a successor of 7e594302a05d + (pick only one of these changesets, possibly with --exact) + [255] + $ hg rewind --hidden --to 'allpredecessors(desc("c_B0"))' --dry-run --as-divergence + abort: not rewinding, a65fceb2324a is a successor of 7e594302a05d + (pick only one of these changesets, possibly with --exact) + [255] + Testing the defaults -------------------- @@ -1195,3 +1206,436 @@ $ hg rewind --keep --to 'desc("amended")' --hidden abort: uncommitted changes [255] + + $ cd .. + +Extra cases related to folds +============================ + +folding with a changeset created after the rewind target +-------------------------------------------------------- + +.. B0 ⇠\ +.. | ⇠ AB2 +.. A0 ⇠ A1 ⇠/ + +this simple test case introduces the idea of making rewind consider different +evolutions of fold components: "parent" evolution of A has more predecessors + + $ hg init extra-fold-case-1 + $ cd extra-fold-case-1 + + $ echo R > R + $ hg ci -qAm R + $ echo A > A + $ hg ci -qAm A0 + $ hg amend -m A1 + $ echo B > B + $ hg ci -qAm B0 + $ hg fold -r 'desc("A1")::' -m AB2 --exact -q + + $ hg glhf --hidden + @ 4:7f9a5314ef94 AB2 (A B) + | + | x 3:16429ed4b6cb B0 (B) + | | + | x 2:3748b241cad8 A1 (A) + |/ + | x 1:fa8956746c52 A0 (A) + |/ + o 0:167e04d3d1b2 R (R) + + +target selection + +when rewinding from a fold, rewind to all of its components (at various points +in their evolution) to not lose work + + $ hg rewind --hidden --to 'desc("A0")' --dry-run + rewinding 7f9a5314ef94 to 2 changesets: fa8956746c52 16429ed4b6cb + $ hg rewind --hidden --to 'desc("B0")' --dry-run + rewinding 7f9a5314ef94 to 2 changesets: 3748b241cad8 16429ed4b6cb + $ hg rewind --from 'desc("AB2")' --dry-run + rewinding 7f9a5314ef94 to 2 changesets: 3748b241cad8 16429ed4b6cb + + $ hg rewind --hidden --to 'allpredecessors(desc("AB2"))' --dry-run + abort: not rewinding, 3748b241cad8 is a successor of fa8956746c52 + (pick only one of these changesets, possibly with --exact) + [255] + + $ cd .. + +folding with a changeset we rebased onto +---------------------------------------- + +.. A0 ⇠ A1 ⇠\ +.. | ⇠ AB2 +.. B0 ⇠/ + +similar to the previous case, but this time evolution of A has more +predecessors and at some point starts to be based on B + + $ hg init extra-fold-case-2 + $ cd extra-fold-case-2 + + $ echo R > R + $ hg ci -qAm R + $ echo A > A + $ hg ci -qAm A0 + $ hg up 'desc("R")' -q + $ echo B > B + $ hg ci -qAm B0 + $ echo A > A + $ hg ci -qAm A1 + $ hg prune -r 'desc("A0")' -s 'desc("A1")' + 1 changesets pruned + + $ hg fold -r 'desc("B0")::' -m AB2 --exact -q + + $ hg glhf --hidden + @ 4:1988e9fe9517 AB2 (A B) + | + | x 3:7175ff74409b A1 (A) + | | + | x 2:d6ed1d624918 B0 (B) + |/ + | x 1:fa8956746c52 A0 (A) + |/ + o 0:167e04d3d1b2 R (R) + + +target selection + +when rewinding from a fold, rewind to all of its components (at various points +in their evolution) to not lose work + + $ hg rewind --hidden --to 'desc("A0")' --dry-run + rewinding 1988e9fe9517 to 2 changesets: fa8956746c52 d6ed1d624918 + $ hg rewind --hidden --to 'desc("B0")' --dry-run + rewinding 1988e9fe9517 to 2 changesets: d6ed1d624918 7175ff74409b + $ hg rewind --from 'desc("AB2")' --dry-run + rewinding 1988e9fe9517 to 2 changesets: d6ed1d624918 7175ff74409b + + $ cd .. + +folding with a changeset that rebased on us +------------------------------------------- + +.. B0 ⇠⇠⇠⇠ B1 ⇠\ +.. | | ⇠ AB2 +.. | A0 ⇠ A1 ⇠/ + +now evolutions of A and B have the same amount of changesets, but at point 0 +they aren't yet related + + $ hg init extra-fold-case-3 + $ cd extra-fold-case-3 + + $ echo R > R + $ hg ci -qAm R + $ echo A > A + $ hg ci -qAm A0 + $ hg amend -m A1 + $ hg up 'desc("R")' -q + $ echo B > B + $ hg ci -qAm B0 + $ hg up 'desc("A1")' -q + $ echo B > B + $ hg ci -qAm B1 + $ hg prune -r 'desc("B0")' -s 'desc("B1")' + 1 changesets pruned + + $ hg fold -r 'desc("A1")::' -m AB2 --exact -q + + $ hg glhf --hidden + @ 5:7f9a5314ef94 AB2 (A B) + | + | x 4:fe7a7d317e16 B1 (B) + | | + +---x 3:d6ed1d624918 B0 (B) + | | + | x 2:3748b241cad8 A1 (A) + |/ + | x 1:fa8956746c52 A0 (A) + |/ + o 0:167e04d3d1b2 R (R) + + +target selection + + $ hg rewind --hidden --to 'desc("A0")' --dry-run + rewinding 7f9a5314ef94 to 2 changesets: fa8956746c52 fe7a7d317e16 + $ hg rewind --hidden --to 'desc("B0")' --dry-run + rewinding 7f9a5314ef94 to 2 changesets: 3748b241cad8 d6ed1d624918 + $ hg rewind --hidden --to 'desc("A1")' --dry-run + rewinding 7f9a5314ef94 to 2 changesets: 3748b241cad8 fe7a7d317e16 + $ hg rewind --hidden --to 'desc("B1")' --dry-run + rewinding 7f9a5314ef94 to 2 changesets: 3748b241cad8 fe7a7d317e16 + $ hg rewind --from 'desc("AB2")' --dry-run + rewinding 7f9a5314ef94 to 2 changesets: 3748b241cad8 fe7a7d317e16 + +actual rewind + + $ hg rewind --hidden --to 'desc("A0")' + 1 new orphan changesets + rewound to 2 changesets + (1 changesets obsoleted) + working directory is now at e492d2f9be46 + +after rewind to A0: +- A0' and B1' are successors to AB2 (split using rewind) +- A0' is a successor of A0 (operation: rewind) +- A0' is a child of R (just like A0) +- B1' is a successor of B1 (operation: rewind) +- B1' is a child of A1 (just like B1), and therefore an orphan + + $ hg obslog -a + o 54b340ce1d87 (6) A0 + |\ split(description, meta, parent, content) from 7f9a5314ef94 using rewind by test (Thu Jan 01 00:00:06 1970 +0000) + | | meta-changed(meta) from fa8956746c52 using rewind by test (Thu Jan 01 00:00:06 1970 +0000) + | | + +---@ e492d2f9be46 (7) B1 + | | | split(description, meta, parent, content) from 7f9a5314ef94 using rewind by test (Thu Jan 01 00:00:06 1970 +0000) + | | | meta-changed(meta) from fe7a7d317e16 using rewind by test (Thu Jan 01 00:00:06 1970 +0000) + | | | + x---+ 7f9a5314ef94 (5) AB2 + | | | folded(description, parent, content) from 3748b241cad8, fe7a7d317e16 using fold by test (Thu Jan 01 00:00:06 1970 +0000) + | | | + x | | 3748b241cad8 (2) A1 + |/ / reworded(description) from fa8956746c52 using amend by test (Thu Jan 01 00:00:06 1970 +0000) + | | + | x fe7a7d317e16 (4) B1 + | | rewritten(description, parent) from d6ed1d624918 using prune by test (Thu Jan 01 00:00:06 1970 +0000) + | | + | x d6ed1d624918 (3) B0 + | + x fa8956746c52 (1) A0 + + $ hg glhf + @ 7:e492d2f9be46 B1 (B) + | + | o 6:54b340ce1d87 A0 (A) + | | + x | 2:3748b241cad8 A1 (A) + |/ + o 0:167e04d3d1b2 R (R) + + + $ hg debugobsolete --exclusive -r 'first(head())' + 7f9a5314ef94f5856ee90661268194cc5ce9b332 54b340ce1d87f3593fd9de2a742e7b444e5136ed e492d2f9be46b73c0cfa51709e92db864b8f3ed9 0 (Thu Jan 01 00:00:06 1970 +0000) {'ef1': '15', 'operation': 'rewind', 'user': 'test'} + fa8956746c5294ce3351309133b450c5930f30f5 54b340ce1d87f3593fd9de2a742e7b444e5136ed 4 (Thu Jan 01 00:00:06 1970 +0000) {'ef1': '2', 'operation': 'rewind', 'user': 'test'} + $ hg debugobsolete --exclusive -r 'last(head())' + 7f9a5314ef94f5856ee90661268194cc5ce9b332 54b340ce1d87f3593fd9de2a742e7b444e5136ed e492d2f9be46b73c0cfa51709e92db864b8f3ed9 0 (Thu Jan 01 00:00:06 1970 +0000) {'ef1': '15', 'operation': 'rewind', 'user': 'test'} + fe7a7d317e168a15e8aa43131b54d3256443d728 e492d2f9be46b73c0cfa51709e92db864b8f3ed9 4 (Thu Jan 01 00:00:06 1970 +0000) {'ef1': '2', 'operation': 'rewind', 'user': 'test'} + + $ cd .. + +simple fold with a missing part +------------------------------- + +.. B0 ⇠ (B1) ⇠\ +.. | | ⇠ AB2 +.. A0 ⇠ A1 ⇠/ + +a stack was rewritten, but then a part of it became unknown locally + + $ hg init extra-fold-case-4 + $ cd extra-fold-case-4 + + $ echo R > R + $ hg ci -qAm R + $ echo A > A + $ hg ci -qAm A0 + $ echo B > B + $ hg ci -qAm B0 + $ hg up 'desc("R")' -q + $ echo A > A + $ hg ci -qAm A1 + $ echo B > B + $ hg ci -qAm B1 + $ hg prune -r 'desc("A0")+desc("B0")' -s 'desc("A1")+desc("B1")' --biject + 2 changesets pruned + + $ hg fold -r 'desc("A1") + desc("B1")' -m AB2 --exact -q + + $ hg glhf --hidden + @ 5:1988e9fe9517 AB2 (A B) + | + | x 4:25210d726f52 B1 (B) + | | + | x 3:9c76368ab336 A1 (A) + |/ + | x 2:a07c12c45197 B0 (B) + | | + | x 1:fa8956746c52 A0 (A) + |/ + o 0:167e04d3d1b2 R (R) + + +target selection + + $ hg rewind --hidden --to 'desc("A0")' --dry-run + rewinding 1988e9fe9517 to 2 changesets: fa8956746c52 25210d726f52 + $ hg rewind --hidden --to 'desc("A1")' --dry-run + rewinding 1988e9fe9517 to 2 changesets: 9c76368ab336 25210d726f52 + $ hg rewind --hidden --to 'desc("B1")' --dry-run + rewinding 1988e9fe9517 to 2 changesets: 9c76368ab336 25210d726f52 + +because B0 is a child of A0, we use A0 instead of A1 unless --exact is given + +XXX the semantic of --exact might need clarification here, +XXX for example, shouln't --exact make sure we only rewind to the `--to` target ? + + $ hg rewind --hidden --to 'desc("B0")' --dry-run + rewinding 1988e9fe9517 to 2 changesets: fa8956746c52 a07c12c45197 + $ hg rewind --hidden --to 'desc("B0")' --exact --dry-run + rewinding 1988e9fe9517 to 2 changesets: a07c12c45197 9c76368ab336 + +stripping one of the fold parts + + $ hg strip --config extensions.strip= -r 'desc("B1")' --hidden -q + + $ hg glhf --hidden + @ 4:1988e9fe9517 AB2 (A B) + | + | x 3:9c76368ab336 A1 (A) + |/ + | x 2:a07c12c45197 B0 (B) + | | + | x 1:fa8956746c52 A0 (A) + |/ + o 0:167e04d3d1b2 R (R) + + +target selection + +the obvious challenge here is to somehow work around the missing fold +component, but we can't do much because it is one of the latest predecessors of +AB2 fold + +in future we might have a way to allow rewind to skip changesets unknown +locally and still proceed (and lose the least amount of work possible) + + $ hg rewind --hidden --to 'desc("A0")+desc("B0")' --exact --dry-run + rewinding 1988e9fe9517 to 2 changesets: fa8956746c52 a07c12c45197 + $ hg rewind --hidden --to 'desc("A0")' --dry-run + abort: not rewinding, some predecessors are unknown locally: 25210d726f52 + (try selecting all changesets to rewind to manually, possibly with --exact) + [255] + $ hg rewind --hidden --to 'desc("A1")' --dry-run + abort: not rewinding, some predecessors are unknown locally: 25210d726f52 + (try selecting all changesets to rewind to manually, possibly with --exact) + [255] + +XXX the semantic of --exact might need clarification here, +XXX for example, shouln't --exact make sure we only rewind to the `--to` target ? + + $ hg rewind --hidden --to 'desc("A1")' --exact --dry-run + abort: not rewinding, some predecessors are unknown locally: 25210d726f52 + (try selecting all changesets to rewind to manually, possibly with --exact) + [255] + $ hg rewind --from 'desc("AB2")' --dry-run + abort: not rewinding, some predecessors are unknown locally: 25210d726f52 + (try selecting all changesets to rewind to manually, possibly with --exact) + [255] + $ hg rewind --from 'desc("AB2")' --exact --dry-run + abort: not rewinding, some predecessors are unknown locally: 25210d726f52 + (try selecting all changesets to rewind to manually, possibly with --exact) + [255] + + $ cd .. + +split and then fold with a missing part +--------------------------------------- + +.. /⇠ (C1) ⇠\ +.. BC0 ⇠ | \ +.. | \⇠ B1 ⇠ AC2 +.. A0 ⇠⇠⇠⇠⇠⇠⇠⇠⇠⇠⇠/ + +here we have a case when walking successors and then predecessors of target +revisions just once might not be enough, because it's a more complex DAG with a +changeset missing from local repo + + $ hg init extra-fold-case-5 + $ cd extra-fold-case-5 + + $ echo R > R + $ hg ci -qAm R + $ echo A > A + $ hg ci -qAm A0 + $ echo B > B + $ echo C > C + $ hg ci -qAm BC0 + $ hg up 'desc("A0")' -q + $ echo B > B + $ hg ci -qAm B1 + $ echo C > C + $ hg ci -qAm C1 + + $ hg prune -r 'desc("BC0")' -s 'desc("B1")+desc("C1")' --split + 1 changesets pruned + + $ hg up 'desc("R")' -q + $ echo A > A + $ echo C > C + $ hg ci -qAm AC2 + + $ hg prune -r 'desc("A0")+desc("C1")' -s 'desc("AC2")' --fold + 2 changesets pruned + 1 new orphan changesets + + $ hg glhf --hidden + @ 5:9ccaac2e5fbb AC2 (A C) + | + | x 4:2e4ab803d8ae C1 (C) + | | + | * 3:44774eafdc1c B1 (B) + | | + | | x 2:883d75400657 BC0 (B C) + | |/ + | x 1:fa8956746c52 A0 (A) + |/ + o 0:167e04d3d1b2 R (R) + + +target selection + + $ hg rewind --hidden --to 'desc("A0")' --dry-run + rewinding 9ccaac2e5fbb to 2 changesets: fa8956746c52 2e4ab803d8ae + $ hg rewind --hidden --to 'desc("BC0")' --dry-run + rewinding 44774eafdc1c to 1 changesets: 883d75400657 + rewinding 9ccaac2e5fbb to 2 changesets: fa8956746c52 883d75400657 + $ hg rewind --from 'desc("AC2")' --dry-run + rewinding 9ccaac2e5fbb to 2 changesets: fa8956746c52 2e4ab803d8ae + +stripping a component of AC2 fold + + $ hg strip --config extensions.strip= --hidden -r 'desc("C1")' -q + warning: ignoring unknown working parent 9ccaac2e5fbb! + +target selection + +at the moment, there's not much that we can do here because of missing C1 + +in future we might have a way to allow rewind to skip changesets unknown +locally and still proceed (and lose the least amount of work possible) + +XXX the semantic of --exact might need clarification here, +XXX for example, shouln't --exact make sure we only rewind to the `--to` target ? + + $ hg rewind --hidden --to 'desc("A0")' --dry-run + abort: not rewinding, some predecessors are unknown locally: 2e4ab803d8ae + (try selecting all changesets to rewind to manually, possibly with --exact) + [255] + $ hg rewind --hidden --to 'desc("BC0")' --dry-run + rewinding 44774eafdc1c to 1 changesets: 883d75400657 + rewinding 9ccaac2e5fbb to 2 changesets: fa8956746c52 883d75400657 + $ hg rewind --from 'desc("AC2")' --dry-run + abort: not rewinding, some predecessors are unknown locally: 2e4ab803d8ae + (try selecting all changesets to rewind to manually, possibly with --exact) + [255] + $ hg rewind --from 'desc("AC2")' --exact --dry-run + abort: not rewinding, some predecessors are unknown locally: 2e4ab803d8ae + (try selecting all changesets to rewind to manually, possibly with --exact) + [255] diff -r 785b5be835ee -r d161fccccd80 tests/test-split.t --- a/tests/test-split.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-split.t Thu Mar 11 14:32:26 2021 +0800 @@ -6,16 +6,6 @@ $ cat >> $HGRCPATH < [alias] > glog = log -G -T "{rev}:{node|short} {desc|firstline} ({phase})\n" - > [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > split=-d "0 0" - > amend=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish = False > [diff] > git = 1 > unified = 0 diff -r 785b5be835ee -r d161fccccd80 tests/test-stabilize-conflict.t --- a/tests/test-stabilize-conflict.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-stabilize-conflict.t Thu Mar 11 14:32:26 2021 +0800 @@ -9,8 +9,6 @@ > interactive=false > merge=internal:merge > promptecho = True - > [defaults] - > amend=-d "0 0" > [merge-tools] > touch.checkchanged=true > touch.gui=true diff -r 785b5be835ee -r d161fccccd80 tests/test-stabilize-order.t --- a/tests/test-stabilize-order.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-stabilize-order.t Thu Mar 11 14:32:26 2021 +0800 @@ -1,6 +1,4 @@ $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" > [extensions] > EOF $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH @@ -72,8 +70,8 @@ b committing manifest committing changelog - resolving manifests - removing b + resolving manifests (ondisk !) + removing b (ondisk !) $ glog o 6:81b8bbcd5892@default(draft) addb | @@ -95,8 +93,8 @@ move:[3] addc atop:[6] addb hg rebase -r 7a7552255fb5 -d 81b8bbcd5892 - resolving manifests - getting b + resolving manifests (ondisk !) + getting b (ondisk !) resolving manifests getting c committing files: @@ -157,9 +155,9 @@ move:[7] addc atop:[8] addb hg rebase -r 0f691739f917 -d 7a68bc4596ea - resolving manifests - removing c - getting b + resolving manifests (ondisk !) + removing c (ondisk !) + getting b (ondisk !) resolving manifests getting c committing files: diff -r 785b5be835ee -r d161fccccd80 tests/test-topic-fold.t --- a/tests/test-topic-fold.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-topic-fold.t Thu Mar 11 14:32:26 2021 +0800 @@ -2,19 +2,6 @@ ------------------------ $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > split=-d "0 0" - > amend=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish = False - > [diff] - > git = 1 - > unified = 0 > [ui] > interactive = true > [extensions] diff -r 785b5be835ee -r d161fccccd80 tests/test-topic-rebase.t --- a/tests/test-topic-rebase.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-topic-rebase.t Thu Mar 11 14:32:26 2021 +0800 @@ -2,19 +2,6 @@ -------------------------- $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > split=-d "0 0" - > amend=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish = False - > [diff] - > git = 1 - > unified = 0 > [ui] > interactive = true > [extensions] diff -r 785b5be835ee -r d161fccccd80 tests/test-topic-stack.t --- a/tests/test-topic-stack.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-topic-stack.t Thu Mar 11 14:32:26 2021 +0800 @@ -66,7 +66,7 @@ active topic 'other' is now empty (use 'hg topic --clear' to clear it if needed) -After changing the phase of all the changesets in "other" to public, the topic should still be active, but is empty. We should be better at informating the user about it and displaying good data in this case. +After changing the phase of all the changesets in "other" to public, the topic should still be active, but is empty. We should be better at informing the user about it and displaying good data in this case. $ hg topic foo (4 changesets) @@ -461,10 +461,10 @@ s1: c_c s0^ c_b (base) -Case with multiple heads on the topic with unstability involved +Case with multiple heads on the topic with instability involved --------------------------------------------------------------- -We amend the message to make sure the display base pick the right changeset +We amend the message to make sure the display base picks the right changeset $ hg up 'desc(c_d)' 0 files updated, 0 files merged, 2 files removed, 0 files unresolved @@ -751,7 +751,7 @@ Even with some obsolete and orphan changesets (the ordering of each branch of "blue" change because their hash change. we -should stabilize this eventuelly) +should stabilize this eventually) $ hg up 'desc("c_B")' switching to topic red @@ -1015,7 +1015,7 @@ @@ -0,0 +1,1 @@ +zzz -Check that stack ouput still make sense +Check that stack output still makes sense $ hg stack ### topic: blue diff -r 785b5be835ee -r d161fccccd80 tests/test-topic-tutorial.t --- a/tests/test-topic-tutorial.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-topic-tutorial.t Thu Mar 11 14:32:26 2021 +0800 @@ -49,7 +49,7 @@ $ . "$TESTDIR/testlib/docgraph_setup.sh" #rest-ignore #endif -Topic branches are lightweight branches which disappear when changes are +Topic branches are lightweight branches which fade out when changes are finalized (moved to the public phase). They can help users to organize and share their unfinished work. @@ -589,7 +589,7 @@ o 0:38da43f0a2ea Shopping list -The topic information will disappear when we publish the changesets: +The topic information will fade out when we publish the changesets: $ hg topics * food (2 changesets) @@ -1113,7 +1113,7 @@ added 2 changesets with 2 changes to 1 files 2 new obsolescence markers -The published topic has now disappeared, and the other is now marked as +The published topic has now faded out, and the other is now marked as "behind": $ hg topics --verbose diff -r 785b5be835ee -r d161fccccd80 tests/test-topic.t --- a/tests/test-topic.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-topic.t Thu Mar 11 14:32:26 2021 +0800 @@ -15,7 +15,7 @@ $ hg help -e topic topic extension - support for topic branches - Topic branches are lightweight branches which disappear when changes are + Topic branches are lightweight branches which fade out when changes are finalized (move to the public phase). Compared to bookmark, topic is reference carried by each changesets of the @@ -690,7 +690,7 @@ | query is not an open topic, so when we clear the current topic it'll -disappear: +fade out: $ hg topics --clear clearing empty topic "query" diff -r 785b5be835ee -r d161fccccd80 tests/test-touch.t --- a/tests/test-touch.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-touch.t Thu Mar 11 14:32:26 2021 +0800 @@ -2,8 +2,6 @@ $ cat >> $HGRCPATH < [ui] > logtemplate={rev}:{node|short} {desc}\n - > [defaults] - > amend=-d "0 0" > [alias] > glog = log -GT "{rev}: {desc}" > [extensions] diff -r 785b5be835ee -r d161fccccd80 tests/test-tutorial.t --- a/tests/test-tutorial.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-tutorial.t Thu Mar 11 14:32:26 2021 +0800 @@ -13,11 +13,6 @@ > [diff] > # use "git" diff format, clearer and smarter format > git = 1 - > [alias] - > # "-d '0 0'" means that the new commit will be at January 1st 1970. - > # This is used for stable hash during test - > # (this tutorial is automatically tested.) - > amend = amend -d '0 0' > EOF $ hg init local diff -r 785b5be835ee -r d161fccccd80 tests/test-unstability-resolution-result.t --- a/tests/test-unstability-resolution-result.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-unstability-resolution-result.t Thu Mar 11 14:32:26 2021 +0800 @@ -8,8 +8,6 @@ XXX dispatching each these test case in appropriate file would make sense. $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" > [extensions] > hgext.rebase= > EOF diff -r 785b5be835ee -r d161fccccd80 tests/test-unstable-orphan.t --- a/tests/test-unstable-orphan.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-unstable-orphan.t Thu Mar 11 14:32:26 2021 +0800 @@ -6,17 +6,6 @@ instability happens when a changesets has obsolete ancestors. $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" - > fold=-d "0 0" - > [web] - > push_ssl = false - > allow_push = * - > [phases] - > publish = False - > [diff] - > git = 1 - > unified = 0 > [ui] > logtemplate = {rev}:{node|short}@{branch}({phase}) {desc|firstline}\n > [extensions] diff -r 785b5be835ee -r d161fccccd80 tests/test-wireproto-bundle1.t --- a/tests/test-wireproto-bundle1.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-wireproto-bundle1.t Thu Mar 11 14:32:26 2021 +0800 @@ -1,7 +1,5 @@ $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" > [ui] > ssh = "$PYTHON" "$RUNTESTDIR/dummyssh" > [phases] diff -r 785b5be835ee -r d161fccccd80 tests/test-wireproto.t --- a/tests/test-wireproto.t Sun Jan 31 15:57:57 2021 +0800 +++ b/tests/test-wireproto.t Thu Mar 11 14:32:26 2021 +0800 @@ -1,7 +1,5 @@ $ cat >> $HGRCPATH < [defaults] - > amend=-d "0 0" > [experimental] > obsmarkers-exchange-debug=true > bundle2-exp=true