--- a/README Tue Jun 23 15:32:15 2015 -0700
+++ b/README Tue Jun 23 15:32:47 2015 -0700
@@ -51,6 +51,20 @@
Changelog
=========
+5.2.0 --
+
+- evolve: gain a --rev option to control what revisions to evolve (issue4391)
+- evolve: revision are processed in the order they stack on destination
+- evolve: properly skip unstable revision with non-evolved unstable parent
+- evolve: gain --unstable --divergent --bumped flag to select the trouble
+- evolve: issue more useful error message and hint when evolve has nothing to
+ do as invocated.
+- evolve: bare `hg evolve` commands now abort when multiple changesets could be
+ a target.
+- evolve: `hg evolve --all` only evolve changeset that will end up as
+ descendant of the current working copy. The old behavior of `--all`
+ in now in `--all --any`.
+
5.1.5 -- 2015-06-23
- minor documentation cleanup
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/directaccess.py Tue Jun 23 15:32:47 2015 -0700
@@ -0,0 +1,175 @@
+""" This extension provides direct access
+It is the ability to refer and access hidden sha in commands provided that you
+know their value.
+For example hg log -r xxx where xxx is a commit has should work whether xxx is
+hidden or not as we assume that the user knows what he is doing when referring
+to xxx.
+"""
+from mercurial import extensions
+from mercurial import cmdutil
+from mercurial import repoview
+from mercurial import branchmap
+from mercurial import revset
+from mercurial import error
+from mercurial import commands
+from mercurial import hg
+from mercurial.i18n import _
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+
+# By default, all the commands have directaccess with warnings
+# List of commands that have no directaccess and directaccess with no warning
+directaccesslevel = [
+ # Format:
+ # ('nowarning', 'evolve', 'prune'),
+ # means: no directaccess warning, for the command in evolve named prune
+ #
+ # ('error', None, 'serve'),
+ # means: no directaccess for the command in core named serve
+ #
+ # The list is ordered alphabetically by command names, starting with all
+ # the commands in core then all the commands in the extensions
+ #
+ # The general guideline is:
+ # - remove directaccess warnings for read only commands
+ # - no direct access for commands with consequences outside of the repo
+ # - leave directaccess warnings for all the other commands
+ #
+ ('nowarning', None, 'annotate'),
+ ('nowarning', None, 'archive'),
+ ('nowarning', None, 'bisect'),
+ ('nowarning', None, 'bookmarks'),
+ ('nowarning', None, 'bundle'),
+ ('nowarning', None, 'cat'),
+ ('nowarning', None, 'diff'),
+ ('nowarning', None, 'export'),
+ ('nowarning', None, 'identify'),
+ ('nowarning', None, 'incoming'),
+ ('nowarning', None, 'log'),
+ ('nowarning', None, 'manifest'),
+ ('error', None, 'outgoing'), # confusing if push errors and not outgoing
+ ('error', None, 'push'), # destructive
+ ('nowarning', None, 'revert'),
+ ('error', None, 'serve'),
+ ('nowarning', None, 'tags'),
+ ('nowarning', None, 'unbundle'),
+ ('nowarning', None, 'update'),
+]
+
+def reposetup(ui, repo):
+ repo._explicitaccess = set()
+
+def _computehidden(repo):
+ hidden = repoview.filterrevs(repo, 'visible')
+ cl = repo.changelog
+ dynamic = hidden & repo._explicitaccess
+ if dynamic:
+ blocked = cl.ancestors(dynamic, inclusive=True)
+ hidden = frozenset(r for r in hidden if r not in blocked)
+ return hidden
+
+def setupdirectaccess():
+ """ Add two new filtername that behave like visible to provide direct access
+ and direct access with warning. Wraps the commands to setup direct access """
+ repoview.filtertable.update({'visible-directaccess-nowarn': _computehidden})
+ repoview.filtertable.update({'visible-directaccess-warn': _computehidden})
+ branchmap.subsettable['visible-directaccess-nowarn'] = 'visible'
+ branchmap.subsettable['visible-directaccess-warn'] = 'visible'
+
+ for warn, ext, cmd in directaccesslevel:
+ try:
+ cmdtable = extensions.find(ext).cmdtable if ext else commands.table
+ wrapper = wrapwitherror if warn == 'error' else wrapwithoutwarning
+ extensions.wrapcommand(cmdtable, cmd, wrapper)
+ except (error.UnknownCommand, KeyError):
+ pass
+
+def wrapwitherror(orig, ui, repo, *args, **kwargs):
+ if repo and repo.filtername == 'visible-directaccess-warn':
+ repo = repo.filtered('visible')
+ return orig(ui, repo, *args, **kwargs)
+
+def wrapwithoutwarning(orig, ui, repo, *args, **kwargs):
+ if repo and repo.filtername == 'visible-directaccess-warn':
+ repo = repo.filtered("visible-directaccess-nowarn")
+ return orig(ui, repo, *args, **kwargs)
+
+def uisetup(ui):
+ """ Change ordering of extensions to ensure that directaccess extsetup comes
+ after the one of the extensions in the loadsafter list """
+ loadsafter = ui.configlist('directaccess','loadsafter')
+ order = list(extensions._order)
+ directaccesidx = order.index('directaccess')
+
+ # The min idx for directaccess to load after all the extensions in loadafter
+ minidxdirectaccess = directaccesidx
+
+ for ext in loadsafter:
+ try:
+ minidxdirectaccess = max(minidxdirectaccess, order.index(ext))
+ except ValueError:
+ pass # extension not loaded
+
+ if minidxdirectaccess > directaccesidx:
+ order.insert(minidxdirectaccess + 1, 'directaccess')
+ order.remove('directaccess')
+ extensions._order = order
+
+def _repository(orig, *args, **kwargs):
+ """Make visible-directaccess-warn the default filter for new repos"""
+ repo = orig(*args, **kwargs)
+ return repo.filtered("visible-directaccess-warn")
+
+def extsetup(ui):
+ extensions.wrapfunction(revset, 'posttreebuilthook', _posttreebuilthook)
+ extensions.wrapfunction(hg, 'repository', _repository)
+ setupdirectaccess()
+
+def gethashsymbols(tree):
+ # Returns the list of symbols of the tree that look like hashes
+ # for example for the revset 3::abe3ff it will return ('abe3ff')
+ if not tree:
+ return []
+
+ if len(tree) == 2 and tree[0] == "symbol":
+ try:
+ int(tree[1])
+ return []
+ except ValueError as e:
+ return [tree[1]]
+ elif len(tree) == 3:
+ return gethashsymbols(tree[1]) + gethashsymbols(tree[2])
+ else:
+ return []
+
+def _posttreebuilthook(orig, tree, repo):
+ # This is use to enabled direct hash access
+ # We extract the symbols that look like hashes and add them to the
+ # explicitaccess set
+ orig(tree, repo)
+ filternm = ""
+ if repo is not None:
+ filternm = repo.filtername
+ if filternm is not None and filternm.startswith('visible-directaccess'):
+ prelength = len(repo._explicitaccess)
+ accessbefore = set(repo._explicitaccess)
+ repo.symbols = gethashsymbols(tree)
+ cl = repo.unfiltered().changelog
+ for node in repo.symbols:
+ try:
+ node = cl._partialmatch(node)
+ except error.LookupError:
+ node = None
+ if node is not None:
+ rev = cl.rev(node)
+ if rev not in repo.changelog:
+ repo._explicitaccess.add(rev)
+ if prelength != len(repo._explicitaccess):
+ if repo.filtername != 'visible-directaccess-nowarn':
+ unhiddencommits = repo._explicitaccess - accessbefore
+ repo.ui.warn( _("Warning: accessing hidden changesets %s "
+ "for write operation\n") %
+ (",".join([str(repo.unfiltered()[l])
+ for l in unhiddencommits])))
+ repo.invalidatevolatilesets()
--- a/hgext/evolve.py Tue Jun 23 15:32:15 2015 -0700
+++ b/hgext/evolve.py Tue Jun 23 15:32:47 2015 -0700
@@ -23,11 +23,48 @@
testedwith = '3.3.3 3.4.1'
buglink = 'http://bz.selenic.com/'
+
+evolutionhelptext = """
+Obsolescence markers make it possible to mark changesets that have been
+deleted or superset in a new version of the changeset.
+
+Unlike the previous way of handling such changes, by stripping the old
+changesets from the repository, obsolescence markers can be propagated
+between repositories. This allows for a safe and simple way of exchanging
+mutable history and altering it after the fact. Changeset phases are
+respected, such that only draft and secret changesets can be altered (see
+:hg:`hg phases` for details).
+
+Obsolescence is tracked using "obsolete markers", a piece of metadata
+tracking which changesets have been made obsolete, potential successors for
+a given changeset, the moment the changeset was marked as obsolete, and the
+user who performed the rewriting operation. The markers are stored
+separately from standard changeset data can be exchanged without any of the
+precursor changesets, preventing unnecessary exchange of obsolescence data.
+
+The complete set of obsolescence markers describes a history of changeset
+modifications that is orthogonal to the repository history of file
+modifications. This changeset history allows for detection and automatic
+resolution of edge cases arising from multiple users rewriting the same part
+of history concurrently.
+
+Current feature status
+======================
+
+This feature is still in development. If you see this help, you have enable an
+extension that turned this feature on.
+
+Obsolescence markers will be exchanged between repositories that explicitly
+assert support for the obsolescence feature (this can currently only be done
+via an extension).""".strip()
+
+
import sys, os
import random
from StringIO import StringIO
import struct
import re
+import collections
import socket
import errno
sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
@@ -45,6 +82,8 @@
except (ImportError, AttributeError):
gboptslist = gboptsmap = None
+# Flags for enabling optional parts of evolve
+commandopt = 'allnewcommands'
from mercurial import bookmarks
from mercurial import cmdutil
@@ -54,6 +93,7 @@
from mercurial import error
from mercurial import exchange
from mercurial import extensions
+from mercurial import help
from mercurial import httppeer
from mercurial import hg
from mercurial import lock as lockmod
@@ -144,8 +184,11 @@
"""
for cont, funcname, func in self._duckpunchers:
setattr(cont, funcname, func)
- for command, wrapper in self._commandwrappers:
- extensions.wrapcommand(commands.table, command, wrapper)
+ for command, wrapper, opts in self._commandwrappers:
+ entry = extensions.wrapcommand(commands.table, command, wrapper)
+ if opts:
+ for short, long, val, msg in opts:
+ entry[1].append((short, long, val, msg))
for cont, funcname, wrapper in self._functionwrappers:
extensions.wrapfunction(cont, funcname, wrapper)
for c in self._uicallables:
@@ -166,13 +209,20 @@
revset.symbols[name] = symbol
for name, kw in self._templatekws:
templatekw.keywords[name] = kw
- for ext, command, wrapper in self._extcommandwrappers:
+ for ext, command, wrapper, opts in self._extcommandwrappers:
if ext not in knownexts:
- e = extensions.find(ext)
- if e is None:
- raise util.Abort('extension %s not found' % ext)
+ try:
+ e = extensions.find(ext)
+ except KeyError:
+ # Extension isn't enabled, so don't bother trying to wrap
+ # it.
+ continue
knownexts[ext] = e.cmdtable
- extensions.wrapcommand(knownexts[ext], commands, wrapper)
+ entry = extensions.wrapcommand(knownexts[ext], command, wrapper)
+ if opts:
+ for short, long, val, msg in opts:
+ entry[1].append((short, long, val, msg))
+
for c in self._extcallables:
c(ui)
@@ -260,7 +310,7 @@
return keyword
return dec
- def wrapcommand(self, command, extension=None):
+ def wrapcommand(self, command, extension=None, opts=[]):
"""Decorated function is a command wrapper
The name of the command must be given as the decorator argument.
@@ -279,12 +329,16 @@
ui.note('Barry!')
return orig(ui, repo, *args, **kwargs)
+ The `opts` argument allows specifying additional arguments for the
+ command.
+
"""
def dec(wrapper):
if extension is None:
- self._commandwrappers.append((command, wrapper))
+ self._commandwrappers.append((command, wrapper, opts))
else:
- self._extcommandwrappers.append((extension, command, wrapper))
+ self._extcommandwrappers.append((extension, command, wrapper,
+ opts))
return wrapper
return dec
@@ -330,6 +384,31 @@
reposetup = eh.final_reposetup
#####################################################################
+### Option configuration ###
+#####################################################################
+
+@eh.reposetup # must be the first of its kin.
+def _configureoptions(ui, repo):
+ # If no capabilities are specified, enable everything.
+ # This is so existing evolve users don't need to change their config.
+ evolveopts = ui.configlist('experimental', 'evolution')
+ if not evolveopts:
+ evolveopts = ['all']
+ ui.setconfig('experimental', 'evolution', evolveopts)
+
+@eh.uisetup
+def _configurecmdoptions(ui):
+ # Unregister evolve commands if the command capability is not specified.
+ #
+ # This must be in the same function as the option configuration above to
+ # guarantee it happens after the above configuration, but before the
+ # extsetup functions.
+ evolveopts = ui.configlist('experimental', 'evolution')
+ if evolveopts and (commandopt not in evolveopts and
+ 'all' not in evolveopts):
+ cmdtable.clear()
+
+#####################################################################
### experimental behavior ###
#####################################################################
@@ -590,9 +669,16 @@
@eh.wrapcommand("pull")
def wrapmayobsoletewc(origfn, ui, repo, *args, **opts):
"""Warn that the working directory parent is an obsolete changeset"""
- res = origfn(ui, repo, *args, **opts)
- if repo['.'].obsolete():
- ui.warn(_('working directory parent is obsolete!\n'))
+ def warnobsolete():
+ if repo['.'].obsolete():
+ ui.warn(_('working directory parent is obsolete!\n'))
+ wlock = None
+ try:
+ wlock = repo.wlock()
+ repo._afterlock(warnobsolete)
+ res = origfn(ui, repo, *args, **opts)
+ finally:
+ lockmod.release(wlock)
return res
# XXX this could wrap transaction code
@@ -962,7 +1048,11 @@
This function is loosely based on the extensions.wrapcommand function.
'''
- aliases, entry = cmdutil.findcmd(newalias, cmdtable)
+ try:
+ aliases, entry = cmdutil.findcmd(newalias, cmdtable)
+ except error.UnknownCommand:
+ # Commands may be disabled
+ return
for alias, e in cmdtable.iteritems():
if e is entry:
break
@@ -1025,6 +1115,23 @@
@command('debugobsstorestat', [], '')
def cmddebugobsstorestat(ui, repo):
+ def _updateclustermap(nodes, mark, clustersmap):
+ c = (set(nodes), set([mark]))
+ toproceed = set(nodes)
+ while toproceed:
+ n = toproceed.pop()
+ other = clustersmap.get(n)
+ if (other is not None
+ and other is not c):
+ other[0].update(c[0])
+ other[1].update(c[1])
+ for on in c[0]:
+ if on in toproceed:
+ continue
+ clustersmap[on] = other
+ c = other
+ clustersmap[n] = c
+
"""print statistic about obsolescence markers in the repo"""
store = repo.obsstore
unfi = repo.unfiltered()
@@ -1054,42 +1161,12 @@
if parents:
parentsdata += 1
# cluster handling
- nodes = set()
+ nodes = set(mark[1])
nodes.add(mark[0])
- nodes.update(mark[1])
- c = (set(nodes), set([mark]))
-
- toproceed = set(nodes)
- while toproceed:
- n = toproceed.pop()
- other = clustersmap.get(n)
- if (other is not None
- and other is not c):
- other[0].update(c[0])
- other[1].update(c[1])
- for on in c[0]:
- if on in toproceed:
- continue
- clustersmap[on] = other
- c = other
- clustersmap[n] = c
+ _updateclustermap(nodes, mark, clustersmap)
# same with parent data
nodes.update(parents)
- c = (set(nodes), set([mark]))
- toproceed = set(nodes)
- while toproceed:
- n = toproceed.pop()
- other = pclustersmap.get(n)
- if (other is not None
- and other is not c):
- other[0].update(c[0])
- other[1].update(c[1])
- for on in c[0]:
- if on in toproceed:
- continue
- pclustersmap[on] = other
- c = other
- pclustersmap[n] = c
+ _updateclustermap(nodes, mark, pclustersmap)
# freezing the result
for c in clustersmap.values():
@@ -1143,216 +1220,148 @@
mean = sum(len(x[1]) for x in allpclusters) // nbcluster
ui.write(' mean length: %9i\n' % mean)
-@command('^evolve|stabilize|solve',
- [('n', 'dry-run', False,
- 'do not perform actions, just print what would be done'),
- ('', 'confirm', False,
- 'ask for confirmation before performing the action'),
- ('A', 'any', False, 'also consider troubled changesets unrelated to current working directory'),
- ('a', 'all', False, 'evolve all troubled changesets in the repo '
- '(implies any)'),
- ('c', 'continue', False, 'continue an interrupted evolution'),
- ] + mergetoolopts,
- _('[OPTIONS]...'))
-def evolve(ui, repo, **opts):
- """solve trouble in your repository
-
- - rebase unstable changesets to make them stable again,
- - create proper diffs from bumped changesets,
- - merge divergent changesets,
- - update to a successor if the working directory parent is
- obsolete
-
- By default a single changeset is evolved for each invocation and only
- troubled changesets that would evolve as a descendant of the current
- working directory will be considered. See --all and --any options to change
- this behavior.
-
- - For unstable, this means taking the first which could be rebased as a
- child of the working directory parent revision or one of its descendants
- and rebasing it.
-
- - For divergent, this means taking "." if applicable.
-
- With --any, evolve picks any troubled changeset to repair.
-
- The working directory is updated to the newly created revision.
- """
-
- contopt = opts['continue']
- anyopt = opts['any']
- allopt = opts['all']
- dryrunopt = opts['dry_run']
- confirmopt = opts['confirm']
- ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve')
-
- startnode = repo['.']
-
- if contopt:
- if anyopt:
- raise util.Abort('cannot specify both "--any" and "--continue"')
- if allopt:
- raise util.Abort('cannot specify both "--all" and "--continue"')
- graftcmd = commands.table['graft'][0]
- return graftcmd(ui, repo, old_obsolete=True, **{'continue': True})
-
- tro = _picknexttroubled(ui, repo, anyopt or allopt)
- if tro is None:
- if repo['.'].obsolete():
- displayer = cmdutil.show_changeset(
- ui, repo, {'template': shorttemplate})
- successors = set()
-
- for successorsset in obsolete.successorssets(repo, repo['.'].node()):
- for nodeid in successorsset:
- successors.add(repo[nodeid])
-
- if not successors:
- ui.warn(_('parent is obsolete without successors; ' +
- 'likely killed\n'))
- return 2
-
- elif len(successors) > 1:
- ui.warn(_('parent is obsolete with multiple successors:\n'))
-
- for ctx in sorted(successors, key=lambda ctx: ctx.rev()):
- displayer.show(ctx)
-
- return 2
-
+def _solveone(ui, repo, ctx, dryrun, confirm, progresscb, category):
+ """Resolve the troubles affecting one revision"""
+ wlock = lock = tr = None
+ try:
+ wlock = repo.wlock()
+ lock = repo.lock()
+ tr = repo.transaction("evolve")
+ if 'unstable' == category:
+ result = _solveunstable(ui, repo, ctx, dryrun, confirm, progresscb)
+ elif 'bumped' == category:
+ result = _solvebumped(ui, repo, ctx, dryrun, confirm, progresscb)
+ elif 'divergent' == category:
+ result = _solvedivergent(ui, repo, ctx, dryrun, confirm,
+ progresscb)
+ else:
+ assert False, "unknown trouble category: %s" % (category)
+ tr.close()
+ return result
+ finally:
+ lockmod.release(tr, lock, wlock)
+
+def _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat):
+ """Used by the evolve function to display an error message when
+ no troubles can be resolved"""
+ troublecategories = ['bumped', 'divergent', 'unstable']
+ unselectedcategories = [c for c in troublecategories if c != targetcat]
+ msg = None
+ hint = None
+
+ troubled = {
+ "unstable": repo.revs("unstable()"),
+ "divergent": repo.revs("divergent()"),
+ "bumped": repo.revs("bumped()"),
+ "all": repo.revs("troubled()"),
+ }
+
+
+ hintmap = {
+ 'bumped': _("do you want to use --bumped"),
+ 'bumped+divergent': _("do you want to use --bumped or --divergent"),
+ 'bumped+unstable': _("do you want to use --bumped or --unstable"),
+ 'divergent': _("do you want to use --divergent"),
+ 'divergent+unstable': _("do you want to use --divergent"
+ " or --unstable"),
+ 'unstable': _("do you want to use --unstable"),
+ 'any+bumped': _("do you want to use --any (or --rev) and --bumped"),
+ 'any+bumped+divergent': _("do you want to use --any (or --rev) and"
+ " --bumped or --divergent"),
+ 'any+bumped+unstable': _("do you want to use --any (or --rev) and"
+ "--bumped or --unstable"),
+ 'any+divergent': _("do you want to use --any (or --rev) and"
+ " --divergent"),
+ 'any+divergent+unstable': _("do you want to use --any (or --rev)"
+ " and --divergent or --unstable"),
+ 'any+unstable': _("do you want to use --any (or --rev)"
+ "and --unstable"),
+ }
+
+ if revopt:
+ revs = scmutil.revrange(repo, revopt)
+ if not revs:
+ msg = _("set of specified revisions is empty")
+ else:
+ msg = _("no %s changesets in specified revisions") % targetcat
+ othertroubles = []
+ for cat in unselectedcategories:
+ if revs & troubled[cat]:
+ othertroubles.append(cat)
+ if othertroubles:
+ hint = hintmap['+'.join(othertroubles)]
+
+ elif anyopt:
+ msg = _("no %s changesets to evolve") % targetcat
+ othertroubles = []
+ for cat in unselectedcategories:
+ if troubled[cat]:
+ othertroubles.append(cat)
+ if othertroubles:
+ hint = hintmap['+'.join(othertroubles)]
+
+ else:
+ # evolve without any option = relative to the current wdir
+ if targetcat == 'unstable':
+ msg = _("nothing to evolve on current working copy parent")
+ else:
+ msg = _("current working copy parent is not %s") % targetcat
+
+ p1 = repo['.'].rev()
+ othertroubles = []
+ for cat in unselectedcategories:
+ if p1 in troubled[cat]:
+ othertroubles.append(cat)
+ if othertroubles:
+ hint = hintmap['+'.join(othertroubles)]
+ else:
+ l = len(troubled[targetcat])
+ if l:
+ hint = (_("%d other %s in the repository, do you want --any or --rev")
+ % (l, targetcat))
else:
- ctx = successors.pop()
-
- ui.status(_('update:'))
- if not ui.quiet:
- displayer.show(ctx)
-
- if dryrunopt:
- return 0
+ othertroubles = []
+ for cat in unselectedcategories:
+ if troubled[cat]:
+ othertroubles.append(cat)
+ if othertroubles:
+ hint = hintmap['any+'+('+'.join(othertroubles))]
else:
- res = hg.update(repo, ctx.rev())
- if ctx != startnode:
- ui.status(_('working directory is now at %s\n') % ctx)
- return res
-
- troubled = repo.revs('troubled()')
- if troubled:
- ui.write_err(_('nothing to evolve here\n'))
- ui.status(_('(%i troubled changesets, do you want --any ?)\n')
- % len(troubled))
- return 2
- else:
- ui.write_err(_('no troubled changesets\n'))
- return 1
-
- def progresscb():
- if allopt:
- ui.progress('evolve', seen, unit='changesets', total=count)
- seen = 1
- count = allopt and _counttroubled(ui, repo) or 1
-
- while tro is not None:
- progresscb()
- wlock = lock = tr = None
- try:
- wlock = repo.wlock()
- lock = repo.lock()
- tr = repo.transaction("evolve")
- result = _evolveany(ui, repo, tro, dryrunopt, confirmopt,
- progresscb=progresscb)
- tr.close()
- finally:
- lockmod.release(tr, lock, wlock)
- progresscb()
- seen += 1
- if not allopt:
- if repo['.'] != startnode:
- ui.status(_('working directory is now at %s\n') % repo['.'])
- return result
- progresscb()
- tro = _picknexttroubled(ui, repo, anyopt or allopt)
-
- if allopt:
+ msg = _("no troubled changesets")
+
+ assert msg is not None
+ ui.write_err(msg+"\n")
+ if hint:
+ ui.write_err("("+hint+")\n")
+ return 2
+ else:
+ return 1
+
+def _cleanup(ui, repo, startnode, showprogress):
+ if showprogress:
ui.progress('evolve', None)
-
if repo['.'] != startnode:
ui.status(_('working directory is now at %s\n') % repo['.'])
-
-def _evolveany(ui, repo, tro, dryrunopt, confirmopt, progresscb):
- repo = repo.unfiltered()
- tro = repo[tro.rev()]
- cmdutil.bailifchanged(repo)
- troubles = tro.troubles()
- if 'unstable' in troubles:
- return _solveunstable(ui, repo, tro, dryrunopt, confirmopt, progresscb)
- elif 'bumped' in troubles:
- return _solvebumped(ui, repo, tro, dryrunopt, confirmopt, progresscb)
- elif 'divergent' in troubles:
- return _solvedivergent(ui, repo, tro, dryrunopt, confirmopt,
- progresscb)
- else:
- assert False # WHAT? unknown troubles
-
-def _counttroubled(ui, repo):
- """Count the amount of troubled changesets"""
- troubled = set()
- troubled.update(getrevs(repo, 'unstable'))
- troubled.update(getrevs(repo, 'bumped'))
- troubled.update(getrevs(repo, 'divergent'))
- return len(troubled)
-
-def _picknexttroubled(ui, repo, pickany=False, progresscb=None):
- """Pick a the next trouble changeset to solve"""
- if progresscb: progresscb()
- tro = _stabilizableunstable(repo, repo['.'])
- if tro is None:
- wdp = repo['.']
- if 'divergent' in wdp.troubles():
- tro = wdp
- if tro is None and pickany:
- troubled = list(repo.set('unstable()'))
- if not troubled:
- troubled = list(repo.set('bumped()'))
- if not troubled:
- troubled = list(repo.set('divergent()'))
- if troubled:
- tro = troubled[0]
-
- return tro
-
-def _stabilizableunstable(repo, pctx):
- """Return a changectx for an unstable changeset which can be
- stabilized on top of pctx or one of its descendants. None if none
- can be found.
+class MultipleSuccessorsError(RuntimeError):
+ """Exception raised by _singlesuccessor when multiple sucessors sets exists
+
+ The object contains the list of successorssets in its 'successorssets'
+ attribute to call to easily recover.
"""
- def selfanddescendants(repo, pctx):
- yield pctx
- for prec in repo.set('allprecursors(%d)', pctx):
- yield prec
- for ctx in pctx.descendants():
- yield ctx
- for prec in repo.set('allprecursors(%d)', ctx):
- yield prec
-
- # Look for an unstable which can be stabilized as a child of
- # node. The unstable must be a child of one of node predecessors.
- directdesc = set([pctx.rev()])
- for ctx in selfanddescendants(repo, pctx):
- for child in ctx.children():
- if ctx.rev() in directdesc and not child.obsolete():
- directdesc.add(child.rev())
- elif child.unstable():
- return child
- return None
-
-def _solveunstable(ui, repo, orig, dryrun=False, confirm=False,
- progresscb=None):
- """Stabilize a unstable changeset"""
- obs = orig.parents()[0]
- if not obs.obsolete():
- obs = orig.parents()[1] # second parent is obsolete ?
- assert obs.obsolete()
+
+ def __init__(self, successorssets):
+ self.successorssets = successorssets
+
+def _singlesuccessor(repo, p):
+ """returns p (as rev) if not obsolete or its unique latest successors
+
+ fail if there are no such successor"""
+
+ if not p.obsolete():
+ return p.rev()
+ obs = repo[p]
+ ui = repo.ui
newer = obsolete.successorssets(repo, obs.node())
# search of a parent which is not killed
while not newer or newer == [()]:
@@ -1362,11 +1371,309 @@
obs = obs.parents()[0]
newer = obsolete.successorssets(repo, obs.node())
if len(newer) > 1:
- raise util.Abort(_("conflict rewriting. can't choose destination\n"))
+ raise MultipleSuccessorsError(newer)
+
+ return repo[newer[0][0]].rev()
+
+def builddependencies(repo, revs):
+ """returns dependency graphs giving an order to solve instability of revs
+ (see _orderrevs for more information on usage)"""
+
+ # For each troubled revision we keep track of what instability if any should
+ # be resolved in order to resolve it. Example:
+ # dependencies = {3: [6], 6:[]}
+ # Means that: 6 has no dependency, 3 depends on 6 to be solved
+ dependencies = {}
+ # rdependencies is the inverted dict of dependencies
+ rdependencies = collections.defaultdict(set)
+
+ for r in revs:
+ dependencies[r] = set()
+ for p in repo[r].parents():
+ try:
+ succ = _singlesuccessor(repo, p)
+ except MultipleSuccessorsError, exc:
+ dependencies[r] = exc.successorssets
+ continue
+ if succ in revs:
+ dependencies[r].add(succ)
+ rdependencies[succ].add(r)
+ return dependencies, rdependencies
+
+def _selectrevs(repo, allopt, revopt, anyopt, targetcat):
+ """select troubles in repo matching according to given options"""
+ revs = set()
+ if allopt or revopt:
+ revs = repo.revs(targetcat+'()')
+ if revopt:
+ revs = scmutil.revrange(repo, revopt) & revs
+ elif not anyopt and targetcat == 'unstable':
+ revs = set(_aspiringdescendant(repo, repo.revs('(.::) - obsolete()::')))
+ elif anyopt:
+ revs = repo.revs('first(%s())' % (targetcat))
+ elif targetcat == 'unstable':
+ revs = set(_aspiringchildren(repo, repo.revs('(.::) - obsolete()::')))
+ if 1 < len(revs):
+ msg = "multiple evolve candidates"
+ hint = (_("select one of %s with --rev")
+ % ', '.join([str(repo[r]) for r in sorted(revs)]))
+ raise error.Abort(msg, hint=hint)
+ elif targetcat in repo['.'].troubles():
+ revs = set([repo['.'].rev()])
+ return revs
+
+
+def _orderrevs(repo, revs):
+ """Compute an ordering to solve instability for the given revs
+
+ - Takes revs a list of instable revisions
+
+ - Returns the same revisions ordered to solve their instability from the
+ bottom to the top of the stack that the stabilization process will produce
+ eventually.
+
+ This ensure the minimal number of stabilization as we can stabilize each
+ revision on its final, stabilized, destination.
+ """
+ # Step 1: Build the dependency graph
+ dependencies, rdependencies = builddependencies(repo, revs)
+ # Step 2: Build the ordering
+ # Remove the revisions with no dependency(A) and add them to the ordering.
+ # Removing these revisions leads to new revisions with no dependency (the
+ # one depending on A) that we can remove from the dependency graph and add
+ # to the ordering. We progress in a similar fashion until the ordering is
+ # built
+ solvablerevs = collections.deque([r for r in sorted(dependencies.keys())
+ if not dependencies[r]])
+ ordering = []
+ while solvablerevs:
+ rev = solvablerevs.popleft()
+ for dependent in rdependencies[rev]:
+ dependencies[dependent].remove(rev)
+ if not dependencies[dependent]:
+ solvablerevs.append(dependent)
+ del dependencies[rev]
+ ordering.append(rev)
+
+ ordering.extend(sorted(dependencies))
+ return ordering
+
+@command('^evolve|stabilize|solve',
+ [('n', 'dry-run', False,
+ 'do not perform actions, just print what would be done'),
+ ('', 'confirm', False,
+ 'ask for confirmation before performing the action'),
+ ('A', 'any', False, 'also consider troubled changesets unrelated to current working directory'),
+ ('r', 'rev', [], 'solves troubles of these revisions'),
+ ('', 'bumped', False, 'solves only bumped changesets'),
+ ('', 'divergent', False, 'solves only divergent changesets'),
+ ('', 'unstable', False, 'solves only unstable changesets (default)'),
+ ('a', 'all', False, 'evolve all troubled changesets related to the current '
+ 'working directory and its descendants'),
+ ('c', 'continue', False, 'continue an interrupted evolution'),
+ ] + mergetoolopts,
+ _('[OPTIONS]...'))
+def evolve(ui, repo, **opts):
+ """solve troubles in your repository
+
+ - rebase unstable changesets to make them stable again,
+ - create proper diffs from bumped changesets,
+ - fuse divergent changesets back together,
+ - update to a successor if the working directory parent is
+ obsolete
+
+ If no argument are passed and the current working copy parent is obsolete,
+ :hg:`evolve` will update the working copy to the successors of this working
+ copy parent. If the working copy parent is not obsolete (and still no
+ argument passed) each invocation of :hg:`evolve` will evolve a single
+ unstable changeset, It will only select a changeset to be evolved if it
+ will result in a new children for the current working copy parent or its
+ descendants. The working copy will be updated on the result
+ (this last behavior will most likely to change in the future).
+ You can evolve all the unstable changesets that will be evolved on the
+ parent of the working copy and all its descendants recursively by using
+ :hg:`evolve` --all.
+
+ You can decide to evolve other categories of trouble using the --divergent
+ and --bumped flags. If no other option are specified, this will try to
+ solve the specified troubles for the working copy parent.
+
+ You can also evolve changesets affected by troubles of the selected
+ category using the --rev options. You can pick the next one anywhere in the
+ repo using --any.
+
+ You can evolve all the changesets affected by troubles of the selected
+ category using --all --any.
+
+ The working directory is updated to the newly created revision.
+ """
+
+ # Options
+ contopt = opts['continue']
+ anyopt = opts['any']
+ allopt = opts['all']
+ startnode = repo['.']
+ dryrunopt = opts['dry_run']
+ confirmopt = opts['confirm']
+ revopt = opts['rev']
+ troublecategories = ['bumped', 'divergent', 'unstable']
+ specifiedcategories = [t for t in troublecategories if opts[t]]
+ targetcat = 'unstable'
+ if 1 < len(specifiedcategories):
+ msg = _('cannot specify more than one trouble category to solve (yet)')
+ raise util.Abort(msg)
+ elif len(specifiedcategories) == 1:
+ targetcat = specifiedcategories[0]
+ elif repo['.'].obsolete():
+ displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
+ # no args and parent is obsolete, update to successors
+ try:
+ ctx = repo[_singlesuccessor(repo, repo['.'])]
+ except MultipleSuccessorsError, exc:
+ repo.ui.write_err('parent is obsolete with multiple successors:\n')
+ for ln in exc.successorssets:
+ for n in ln:
+ displayer.show(repo[n])
+ return 2
+
+
+ ui.status(_('update:'))
+ if not ui.quiet:
+ displayer.show(ctx)
+
+ if dryrunopt:
+ return 0
+ res = hg.update(repo, ctx.rev())
+ if ctx != startnode:
+ ui.status(_('working directory is now at %s\n') % ctx)
+ return res
+
+ ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve')
+ troubled = set(repo.revs('troubled()'))
+
+ # Progress handling
+ seen = 1
+ count = allopt and len(troubled) or 1
+ showprogress = allopt
+
+ def progresscb():
+ if revopt or allopt:
+ ui.progress('evolve', seen, unit='changesets', total=count)
+
+ # Continuation handling
+ if contopt:
+ if anyopt:
+ raise util.Abort('cannot specify both "--any" and "--continue"')
+ if allopt:
+ raise util.Abort('cannot specify both "--all" and "--continue"')
+ graftcmd = commands.table['graft'][0]
+ return graftcmd(ui, repo, old_obsolete=True, **{'continue': True})
+ cmdutil.bailifchanged(repo)
+
+
+ if revopt and allopt:
+ raise util.Abort('cannot specify both "--rev" and "--all"')
+ if revopt and anyopt:
+ raise util.Abort('cannot specify both "--rev" and "--any"')
+
+ revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat)
+
+ if not revs:
+ return _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat)
+
+ # For the progress bar to show
+ count = len(revs)
+ # Order the revisions
+ if targetcat == 'unstable':
+ revs = _orderrevs(repo, revs)
+ for rev in revs:
+ progresscb()
+ _solveone(ui, repo, repo[rev], dryrunopt, confirmopt,
+ progresscb, targetcat)
+ seen += 1
+ progresscb()
+ _cleanup(ui, repo, startnode, showprogress)
+
+def _possibledestination(repo, rev):
+ """return all changesets that may be a new parent for REV"""
+ tonode = repo.changelog.node
+ parents = repo.changelog.parentrevs
+ torev = repo.changelog.rev
+ dest = set()
+ tovisit = list(parents(rev))
+ while tovisit:
+ r = tovisit.pop()
+ succsets = obsolete.successorssets(repo, tonode(r))
+ if not succsets:
+ tovisit.extend(parents(r))
+ else:
+ # We should probably pick only one destination from split
+ # (case where '1 < len(ss)'), This could be the currently tipmost
+ # but logic is less clear when result of the split are now on
+ # multiple branches.
+ for ss in succsets:
+ for n in ss:
+ dest.add(torev(n))
+ return dest
+
+def _aspiringchildren(repo, revs):
+ """Return a list of changectx which can be stabilized on top of pctx or
+ one of its descendants. Empty list if none can be found."""
+ target = set(revs)
+ result = []
+ for r in repo.revs('unstable() - %ld', revs):
+ dest = _possibledestination(repo, r)
+ if target & dest:
+ result.append(r)
+ return result
+
+def _aspiringdescendant(repo, revs):
+ """Return a list of changectx which can be stabilized on top of pctx or
+ one of its descendants recursively. Empty list if none can be found."""
+ target = set(revs)
+ result = set(target)
+ paths = collections.defaultdict(set)
+ for r in repo.revs('unstable() - %ld', revs):
+ for d in _possibledestination(repo, r):
+ paths[d].add(r)
+
+ result = set(target)
+ tovisit = list(revs)
+ while tovisit:
+ base = tovisit.pop()
+ for unstable in paths[base]:
+ if unstable not in result:
+ tovisit.append(unstable)
+ result.add(unstable)
+ return sorted(result - target)
+
+def _solveunstable(ui, repo, orig, dryrun=False, confirm=False,
+ progresscb=None):
+ """Stabilize a unstable changeset"""
+ obs = orig.parents()[0]
+ if not obs.obsolete() and len(orig.parents()) == 2:
+ obs = orig.parents()[1] # second parent is obsolete ?
+
+ if not obs.obsolete():
+ ui.warn("cannot solve instability of %s, skipping\n" % orig)
+ return False
+ newer = obsolete.successorssets(repo, obs.node())
+ # search of a parent which is not killed
+ while not newer or newer == [()]:
+ ui.debug("stabilize target %s is plain dead,"
+ " trying to stabilize on its parent\n" %
+ obs)
+ obs = obs.parents()[0]
+ newer = obsolete.successorssets(repo, obs.node())
+ if len(newer) > 1:
+ msg = _("skipping %s: divergent rewriting. can't choose destination\n" % obs)
+ ui.write_err(msg)
+ return 2
targets = newer[0]
assert targets
if len(targets) > 1:
- raise util.Abort(_("does not handle split parents yet\n"))
+ msg = _("does not handle split parents yet\n")
+ ui.write_err(msg)
return 2
target = targets[0]
displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
@@ -1399,15 +1706,19 @@
def _solvebumped(ui, repo, bumped, dryrun=False, confirm=False,
progresscb=None):
"""Stabilize a bumped changeset"""
+ repo = repo.unfiltered()
+ bumped = repo[bumped.rev()]
# For now we deny bumped merge
if len(bumped.parents()) > 1:
- raise util.Abort('late comer stabilization is confused by bumped'
- ' %s being a merge' % bumped)
+ msg = _('skipping %s : we do not handle merge yet\n' % bumped)
+ ui.write_err(msg)
+ return 2
prec = repo.set('last(allprecursors(%d) and public())', bumped).next()
# For now we deny target merge
if len(prec.parents()) > 1:
- raise util.Abort('late comer evolution is confused by precursors'
- ' %s being a merge' % prec)
+ msg = _('skipping: %s: public version is a merge, this not handled yet\n' % prec)
+ ui.write_err(msg)
+ return 2
displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
if not ui.quiet or confirm:
@@ -1451,6 +1762,9 @@
files = set()
copied = copies.pathcopies(prec, bumped)
precmanifest = prec.manifest()
+ # 3.3.2 needs a list.
+ # future 3.4 don't detect the size change during iteration
+ # this is fishy
for key, val in list(bumped.manifest().iteritems()):
precvalue = precmanifest.get(key, None)
if precvalue is not None:
@@ -1502,40 +1816,51 @@
def _solvedivergent(ui, repo, divergent, dryrun=False, confirm=False,
progresscb=None):
+ repo = repo.unfiltered()
+ divergent = repo[divergent.rev()]
base, others = divergentdata(divergent)
if len(others) > 1:
othersstr = "[%s]" % (','.join([str(i) for i in others]))
- hint = ("changeset %d is divergent with a changeset that got splitted "
- "| into multiple ones:\n[%s]\n"
- "| This is not handled by automatic evolution yet\n"
- "| You have to fallback to manual handling with commands "
- "such as:\n"
- "| - hg touch -D\n"
- "| - hg prune\n"
- "| \n"
- "| You should contact your local evolution Guru for help.\n"
- % (divergent, othersstr))
- raise util.Abort("we do not handle divergence with split yet",
- hint=hint)
+ msg = _("skipping %d:divergent with a changeset that got splitted into multiple ones:\n"
+ "|[%s]\n"
+ "| This is not handled by automatic evolution yet\n"
+ "| You have to fallback to manual handling with commands "
+ "such as:\n"
+ "| - hg touch -D\n"
+ "| - hg prune\n"
+ "| \n"
+ "| You should contact your local evolution Guru for help.\n"
+ % (divergent, othersstr))
+ ui.write_err(msg)
+ return 2
other = others[0]
if divergent.phase() <= phases.public:
- raise util.Abort("we can't resolve this conflict from the public side",
- hint="%s is public, try from %s" % (divergent, other))
+ msg = _("skipping %s: we can't resolve divergence from the public side\n") % divergent
+ ui.write_err(msg)
+ hint = _("(%s is public, try from %s)\n" % (divergent, other))
+ ui.write_err(hint)
+ return 2
if len(other.parents()) > 1:
- raise util.Abort("divergent changeset can't be a merge (yet)",
- hint="You have to fallback to solving this by hand...\n"
- "| This probably means redoing the merge and using "
- "| `hg prune` to kill older version.")
+ msg = _("skipping %s: divergent changeset can't be a merge (yet)\n" % divergent)
+ ui.write_err(msg)
+ hint = _("You have to fallback to solving this by hand...\n"
+ "| This probably means redoing the merge and using \n"
+ "| `hg prune` to kill older version.\n")
+ ui.write_err(hint)
+ return 2
if other.p1() not in divergent.parents():
- raise util.Abort("parents are not common (not handled yet)",
- hint="| %(d)s, %(o)s are not based on the same changeset.\n"
- "| With the current state of its implementation, \n"
- "| evolve does not work in that case.\n"
- "| rebase one of them next to the other and run \n"
- "| this command again.\n"
- "| - either: hg rebase --dest 'p1(%(d)s)' -r %(o)s\n"
- "| - or: hg rebase --dest 'p1(%(o)s)' -r %(d)s"
- % {'d': divergent, 'o': other})
+ msg = _("skipping %s: have a different parent than %s (not handled yet)\n") % (divergent, other)
+ hint = _("| %(d)s, %(o)s are not based on the same changeset.\n"
+ "| With the current state of its implementation, \n"
+ "| evolve does not work in that case.\n"
+ "| rebase one of them next to the other and run \n"
+ "| this command again.\n"
+ "| - either: hg rebase --dest 'p1(%(d)s)' -r %(o)s\n"
+ "| - or: hg rebase --dest 'p1(%(o)s)' -r %(d)s\n"
+ % {'d': divergent, 'o': other})
+ ui.write_err(msg)
+ ui.write_err(hint)
+ return 2
displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
if not ui.quiet or confirm:
@@ -1740,6 +2065,7 @@
[('n', 'new', [], _("successor changeset (DEPRECATED)")),
('s', 'succ', [], _("successor changeset")),
('r', 'rev', [], _("revisions to prune")),
+ ('k', 'keep', None, _("does not modify working copy during prune")),
('', 'biject', False, _("do a 1-1 map between rev and successor ranges")),
('B', 'bookmark', '', _("remove revs only reachable from given"
" bookmark"))] + metadataopts,
@@ -1779,10 +2105,11 @@
if not revs:
raise util.Abort(_('nothing to prune'))
- wlock = lock = None
+ wlock = lock = tr = None
try:
wlock = repo.wlock()
lock = repo.lock()
+ tr = repo.transaction('prune')
# defines pruned changesets
precs = []
revs.sort()
@@ -1796,6 +2123,10 @@
if not precs:
raise util.Abort('nothing to prune')
+ if not obsolete.isenabled(repo, obsolete.allowunstableopt):
+ if repo.revs("(%ld::) - %ld", revs, revs):
+ raise util.Abort(_("cannot prune in the middle of a stack"))
+
# defines successors changesets
sucs = scmutil.revrange(repo, succs)
sucs.sort()
@@ -1813,12 +2144,6 @@
if biject:
relations = [(p, (s,)) for p, s in zip(precs, sucs)]
- # create markers
- obsolete.createmarkers(repo, relations, metadata=metadata)
-
- # informs that changeset have been pruned
- ui.status(_('%i changesets pruned\n') % len(precs))
-
wdp = repo['.']
if len(sucs) == 1 and len(precs) == 1 and wdp in precs:
@@ -1828,27 +2153,55 @@
# update to an unkilled parent
newnode = wdp
- while newnode.obsolete():
+ while newnode in precs or newnode.obsolete():
newnode = newnode.parents()[0]
+
if newnode.node() != wdp.node():
- bookactive = bmactive(repo)
- # Active bookmark that we don't want to delete (with -B option)
- # we deactivate and move it before the update and reactivate it
- # after
- movebookmark = bookactive and not bookmark
- if movebookmark:
- bmdeactivate(repo)
- repo._bookmarks[bookactive] = newnode.node()
- repo._bookmarks.write()
- commands.update(ui, repo, newnode.rev())
- ui.status(_('working directory now at %s\n') % newnode)
- if movebookmark:
- bmactivate(repo, bookactive)
+ if opts.get('keep', False):
+ # This is largely the same as the implementation in
+ # strip.stripcmd(). We might want to refactor this somewhere
+ # common at some point.
+
+ # only reset the dirstate for files that would actually change
+ # between the working context and uctx
+ descendantrevs = repo.revs("%d::." % newnode.rev())
+ changedfiles = []
+ for rev in descendantrevs:
+ # blindly reset the files, regardless of what actually changed
+ changedfiles.extend(repo[rev].files())
+
+ # reset files that only changed in the dirstate too
+ dirstate = repo.dirstate
+ dirchanges = [f for f in dirstate if dirstate[f] != 'n']
+ changedfiles.extend(dirchanges)
+ repo.dirstate.rebuild(newnode.node(), newnode.manifest(), changedfiles)
+ repo.dirstate.write()
+ else:
+ bookactive = bmactive(repo)
+ # Active bookmark that we don't want to delete (with -B option)
+ # we deactivate and move it before the update and reactivate it
+ # after
+ movebookmark = bookactive and not bookmark
+ if movebookmark:
+ bmdeactivate(repo)
+ repo._bookmarks[bookactive] = newnode.node()
+ repo._bookmarks.write()
+ commands.update(ui, repo, newnode.rev())
+ ui.status(_('working directory now at %s\n') % newnode)
+ if movebookmark:
+ bmactivate(repo, bookactive)
# update bookmarks
if bookmark:
_deletebookmark(ui, marks, bookmark)
+
+ # create markers
+ obsolete.createmarkers(repo, relations, metadata=metadata)
+
+ # informs that changeset have been pruned
+ ui.status(_('%i changesets pruned\n') % len(precs))
+
for ctx in repo.unfiltered().set('bookmark() and %ld', precs):
# used to be:
#
@@ -1863,8 +2216,10 @@
updatebookmarks = _bookmarksupdater(repo, ctx.node())
updatebookmarks(dest.node())
break
+
+ tr.close()
finally:
- lockmod.release(lock, wlock)
+ lockmod.release(tr, lock, wlock)
@command('amend|refresh',
[('A', 'addremove', None,
@@ -2053,11 +2408,16 @@
if ctx.p1() == rev or ctx.p2() == rev:
raise util.Abort(_("cannot uncommit to parent changeset"))
+ onahead = old.rev() in repo.changelog.headrevs()
+ disallowunstable = not obsolete.isenabled(repo, obsolete.allowunstableopt)
+ if disallowunstable and not onahead:
+ raise util.Abort(_("cannot uncommit in the middle of a stack"))
+
# Recommit the filtered changeset
tr = repo.transaction('uncommit')
newid = None
- if (pats or opts.get('include') or opts.get('exclude')
- or opts.get('all')):
+ includeorexclude = opts.get('include') or opts.get('exclude')
+ if (pats or includeorexclude or opts.get('all')):
match = scmutil.match(old, pats, opts)
newid = _commitfiltered(repo, old, match, target=rev)
if newid is None:
@@ -2107,6 +2467,31 @@
finally:
lockmod.release(lock, wlock)
+@eh.wrapcommand('strip', extension='strip', opts=[
+ ('', 'bundle', None, _("delete the commit entirely and move it to a "
+ "backup bundle")),
+ ])
+def stripwrapper(orig, ui, repo, *revs, **kwargs):
+ if (not ui.configbool('experimental', 'prunestrip') or
+ kwargs.get('bundle', False)):
+ return orig(ui, repo, *revs, **kwargs)
+
+ if kwargs.get('force'):
+ ui.warn(_("warning: --force has no effect during strip with evolve "
+ "enabled\n"))
+ if kwargs.get('no_backup', False):
+ ui.warn(_("warning: --no-backup has no effect during strips with "
+ "evolve enabled\n"))
+
+ revs = list(revs) + kwargs.pop('rev', [])
+ revs = set(scmutil.revrange(repo, revs))
+ revs = repo.revs("(%ld)::", revs)
+ kwargs['rev'] = []
+ kwargs['new'] = []
+ kwargs['succ'] = []
+ kwargs['biject'] = False
+ return cmdprune(ui, repo, *revs, **kwargs)
+
@command('^touch',
[('r', 'rev', [], 'revision to update'),
('D', 'duplicate', False,
@@ -2233,6 +2618,11 @@
raise util.Abort(_("cannot fold non-linear revisions "
"(multiple heads given)"))
head = repo[heads.first()]
+ disallowunstable = not obsolete.isenabled(repo, obsolete.allowunstableopt)
+ if disallowunstable:
+ if repo.revs("(%ld::) - %ld", revs, revs):
+ raise util.Abort(_("cannot fold chain not ending with a head "\
+ "or with branching"))
wlock = lock = None
try:
wlock = repo.wlock()
@@ -2299,8 +2689,12 @@
@eh.extsetup
def oldevolveextsetup(ui):
for cmd in ['kill', 'uncommit', 'touch', 'fold']:
- entry = extensions.wrapcommand(cmdtable, cmd,
- warnobserrors)
+ try:
+ entry = extensions.wrapcommand(cmdtable, cmd,
+ warnobserrors)
+ except error.UnknownCommand:
+ # Commands may be disabled
+ continue
entry = cmdutil.findcmd('commit', commands.table)[1]
entry[1].append(('o', 'obsolete', [],
@@ -2329,38 +2723,19 @@
topic = 'OBSEXC'
ui.progress(topic, *args, **kwargs)
-if getattr(exchange, '_pushdiscoveryobsmarkers', None) is not None:
- @eh.wrapfunction(exchange, '_pushdiscoveryobsmarkers')
- def _pushdiscoveryobsmarkers(orig, pushop):
- if (obsolete._enabled
- and pushop.repo.obsstore
- and 'obsolete' in pushop.remote.listkeys('namespaces')):
- repo = pushop.repo
- obsexcmsg(repo.ui, "computing relevant nodes\n")
- revs = list(repo.revs('::%ln', pushop.futureheads))
- unfi = repo.unfiltered()
- cl = unfi.changelog
- if not pushop.remote.capable('_evoext_obshash_0'):
- # do not trust core yet
- # return orig(pushop)
- nodes = [cl.node(r) for r in revs]
- if nodes:
- obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
- % len(nodes))
- pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
- else:
- obsexcmsg(repo.ui, "markers already in sync\n")
- pushop.outobsmarkers = []
- pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
- return
-
- common = []
- obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
- % len(revs))
- commonrevs = list(unfi.revs('::%ln', pushop.outgoing.commonheads))
- common = findcommonobsmarkers(pushop.ui, unfi, pushop.remote, commonrevs)
-
- revs = list(unfi.revs('%ld - (::%ln)', revs, common))
+@eh.wrapfunction(exchange, '_pushdiscoveryobsmarkers')
+def _pushdiscoveryobsmarkers(orig, pushop):
+ if (obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
+ and pushop.repo.obsstore
+ and 'obsolete' in pushop.remote.listkeys('namespaces')):
+ repo = pushop.repo
+ obsexcmsg(repo.ui, "computing relevant nodes\n")
+ revs = list(repo.revs('::%ln', pushop.futureheads))
+ unfi = repo.unfiltered()
+ cl = unfi.changelog
+ if not pushop.remote.capable('_evoext_obshash_0'):
+ # do not trust core yet
+ # return orig(pushop)
nodes = [cl.node(r) for r in revs]
if nodes:
obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
@@ -2369,12 +2744,30 @@
else:
obsexcmsg(repo.ui, "markers already in sync\n")
pushop.outobsmarkers = []
+ pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
+ return
+
+ common = []
+ obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
+ % len(revs))
+ commonrevs = list(unfi.revs('::%ln', pushop.outgoing.commonheads))
+ common = findcommonobsmarkers(pushop.ui, unfi, pushop.remote, commonrevs)
+
+ revs = list(unfi.revs('%ld - (::%ln)', revs, common))
+ nodes = [cl.node(r) for r in revs]
+ if nodes:
+ obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
+ % len(nodes))
+ pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
+ else:
+ obsexcmsg(repo.ui, "markers already in sync\n")
+ pushop.outobsmarkers = []
@eh.wrapfunction(wireproto, 'capabilities')
def discocapabilities(orig, repo, proto):
"""wrapper to advertise new capability"""
caps = orig(repo, proto)
- if obsolete._enabled:
+ if obsolete.isenabled(repo, obsolete.exchangeopt):
caps += ' _evoext_obshash_0'
return caps
@@ -2534,7 +2927,7 @@
pushop.ui.debug('try to push obsolete markers to remote\n')
repo = pushop.repo
remote = pushop.remote
- if (obsolete._enabled and repo.obsstore and
+ if (obsolete.isenabled(repo, obsolete.exchangeopt) and repo.obsstore and
'obsolete' in remote.listkeys('namespaces')):
markers = pushop.outobsmarkers
if not markers:
@@ -2609,28 +3002,7 @@
caps.add('_evoext_pushobsmarkers_0')
return caps
-@eh.addattr(localrepo.localpeer, 'evoext_pushobsmarkers_0')
-def local_pushobsmarkers(peer, obsfile):
- data = obsfile.read()
- tr = lock = None
- try:
- lock = peer._repo.lock()
- tr = peer._repo.transaction('pushkey: obsolete markers')
- new = peer._repo.obsstore.mergemarkers(tr, data)
- if new is not None:
- obsexcmsg(peer._repo.ui, "%i obsolescence markers added\n" % new, True)
- tr.close()
- finally:
- lockmod.release(tr, lock)
- peer._repo.hook('evolve_pushobsmarkers')
-
-def srv_pushobsmarkers(repo, proto):
- """wireprotocol command"""
- fp = StringIO()
- proto.redirect()
- proto.getfile(fp)
- data = fp.getvalue()
- fp.close()
+def _pushobsmarkers(repo, data):
tr = lock = None
try:
lock = repo.lock()
@@ -2642,6 +3014,20 @@
finally:
lockmod.release(tr, lock)
repo.hook('evolve_pushobsmarkers')
+
+@eh.addattr(localrepo.localpeer, 'evoext_pushobsmarkers_0')
+def local_pushobsmarkers(peer, obsfile):
+ data = obsfile.read()
+ _pushobsmarkers(peer._repo, data)
+
+def srv_pushobsmarkers(repo, proto):
+ """wireprotocol command"""
+ fp = StringIO()
+ proto.redirect()
+ proto.getfile(fp)
+ data = fp.getvalue()
+ fp.close()
+ _pushobsmarkers(repo, data)
return wireproto.pushres(0)
def _buildpullobsmarkersboundaries(pullop):
@@ -2674,34 +3060,32 @@
kwargs['evo_obscommon'] = common
return ret
-if getattr(exchange, '_getbundleobsmarkerpart', None) is not None:
- @eh.wrapfunction(exchange, '_getbundleobsmarkerpart')
- def _getbundleobsmarkerpart(orig, bundler, repo, source, **kwargs):
- if 'evo_obscommon' not in kwargs:
- return orig(bundler, repo, source, **kwargs)
-
- heads = kwargs.get('heads')
- if kwargs.get('obsmarkers', False):
- if heads is None:
- heads = repo.heads()
- obscommon = kwargs.get('evo_obscommon', ())
- assert obscommon
- obsset = repo.unfiltered().set('::%ln - ::%ln', heads, obscommon)
- subset = [c.node() for c in obsset]
- markers = repo.obsstore.relevantmarkers(subset)
- exchange.buildobsmarkerspart(bundler, markers)
-
- @eh.uisetup
- def installgetbundlepartgen(ui):
- origfunc = exchange.getbundle2partsmapping['obsmarkers']
- def newfunc(*args, **kwargs):
- return _getbundleobsmarkerpart(origfunc, *args, **kwargs)
- exchange.getbundle2partsmapping['obsmarkers'] = newfunc
-
+@eh.wrapfunction(exchange, '_getbundleobsmarkerpart')
+def _getbundleobsmarkerpart(orig, bundler, repo, source, **kwargs):
+ if 'evo_obscommon' not in kwargs:
+ return orig(bundler, repo, source, **kwargs)
+
+ heads = kwargs.get('heads')
+ if kwargs.get('obsmarkers', False):
+ if heads is None:
+ heads = repo.heads()
+ obscommon = kwargs.get('evo_obscommon', ())
+ assert obscommon
+ obsset = repo.unfiltered().set('::%ln - ::%ln', heads, obscommon)
+ subset = [c.node() for c in obsset]
+ markers = repo.obsstore.relevantmarkers(subset)
+ exchange.buildobsmarkerspart(bundler, markers)
+
+@eh.uisetup
+def installgetbundlepartgen(ui):
+ origfunc = exchange.getbundle2partsmapping['obsmarkers']
+ def newfunc(*args, **kwargs):
+ return _getbundleobsmarkerpart(origfunc, *args, **kwargs)
+ exchange.getbundle2partsmapping['obsmarkers'] = newfunc
@eh.wrapfunction(exchange, '_pullobsolete')
def _pullobsolete(orig, pullop):
- if not obsolete._enabled:
+ if not obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
return None
if 'obsmarkers' not in getattr(pullop, 'todosteps', ['obsmarkers']):
return None
@@ -2871,21 +3255,20 @@
_bestformat = max(obsolete.formats.keys())
-if getattr(obsolete, '_checkinvalidmarkers', None) is not None:
- @eh.wrapfunction(obsolete, '_checkinvalidmarkers')
- def _checkinvalidmarkers(orig, markers):
- """search for marker with invalid data and raise error if needed
-
- Exist as a separated function to allow the evolve extension for a more
- subtle handling.
- """
- if 'debugobsconvert' in sys.argv:
- return
- for mark in markers:
- if node.nullid in mark[1]:
- raise util.Abort(_('bad obsolescence marker detected: '
- 'invalid successors nullid'),
- hint=_('You should run `hg debugobsconvert`'))
+@eh.wrapfunction(obsolete, '_checkinvalidmarkers')
+def _checkinvalidmarkers(orig, markers):
+ """search for marker with invalid data and raise error if needed
+
+ Exist as a separated function to allow the evolve extension for a more
+ subtle handling.
+ """
+ if 'debugobsconvert' in sys.argv:
+ return
+ for mark in markers:
+ if node.nullid in mark[1]:
+ raise util.Abort(_('bad obsolescence marker detected: '
+ 'invalid successors nullid'),
+ hint=_('You should run `hg debugobsconvert`'))
@command(
'debugobsconvert',
@@ -2920,7 +3303,7 @@
def capabilities(orig, repo, proto):
"""wrapper to advertise new capability"""
caps = orig(repo, proto)
- if obsolete._enabled:
+ if obsolete.isenabled(repo, obsolete.exchangeopt):
caps += ' _evoext_pushobsmarkers_0'
caps += ' _evoext_pullobsmarkers_0'
caps += ' _evoext_obshash_0'
@@ -2941,3 +3324,16 @@
def newcap(repo, proto):
return capabilities(oldcap, repo, proto)
wireproto.commands['capabilities'] = (newcap, args)
+
+def _helploader():
+ return help.gettext(evolutionhelptext)
+
+@eh.uisetup
+def _setuphelp(ui):
+ for entry in help.helptable:
+ if entry[0] == "evolution":
+ break
+ else:
+ help.helptable.append((["evolution"], _("Safely Rewriting History"),
+ _helploader))
+ help.helptable.sort()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/inhibit.py Tue Jun 23 15:32:47 2015 -0700
@@ -0,0 +1,227 @@
+"""reduce the changesets evolution feature scope for early and noob friendly ui
+
+the full scale changeset evolution have some massive bleeding edge and it is
+very easy for people not very intimate with the concept to end up in intricate
+situation. in order to get some of the benefit sooner, this extension is
+disabling some of the less polished aspect of evolution. it should gradually
+get thinner and thinner as changeset evolution will get more polished. this
+extension is only recommended for large scale organisations. individual user
+should probably stick on using evolution in its current state, understand its
+concept and provide feedback
+
+This extension provides the ability to "inhibit" obsolescence markers. obsolete
+revision can be cheaply brought back to life that way.
+However as the inhibitor are not fitting in an append only model, this is
+incompatible with sharing mutable history.
+"""
+from mercurial import localrepo
+from mercurial import obsolete
+from mercurial import extensions
+from mercurial import cmdutil
+from mercurial import error
+from mercurial import scmutil
+from mercurial import commands
+from mercurial import lock as lockmod
+from mercurial import bookmarks
+from mercurial.i18n import _
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+
+def reposetup(ui, repo):
+
+ class obsinhibitedrepo(repo.__class__):
+
+ @localrepo.storecache('obsinhibit')
+ def _obsinhibit(self):
+ # XXX we should make sure it is invalidated by transaction failure
+ obsinhibit = set()
+ raw = self.sopener.tryread('obsinhibit')
+ for i in xrange(0, len(raw), 20):
+ obsinhibit.add(raw[i:i+20])
+ return obsinhibit
+
+ def commit(self, *args, **kwargs):
+ newnode = super(obsinhibitedrepo, self).commit(*args, **kwargs)
+ if newnode is not None:
+ _inhibitmarkers(repo, [newnode])
+ return newnode
+
+ repo.__class__ = obsinhibitedrepo
+
+def _update(orig, ui, repo, *args, **kwargs):
+ """
+ When moving to a commit we want to inhibit any obsolete commit affecting
+ the changeset we are updating to. In other words we don't want any visible
+ commit to be obsolete.
+ """
+ wlock = None
+ try:
+ # Evolve is running a hook on lock release to display a warning message
+ # if the workind dir's parent is obsolete.
+ # We take the lock here to make sure that we inhibit the parent before
+ # that hook get a chance to run.
+ wlock = repo.wlock()
+ res = orig(ui, repo, *args, **kwargs)
+ newhead = repo['.'].node()
+ _inhibitmarkers(repo, [newhead])
+ return res
+ finally:
+ lockmod.release(wlock)
+
+def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
+ """ Add inhibition markers to every obsolete bookmarks """
+ repo = bkmstoreinst._repo
+ bkmstorenodes = [repo[v].node() for v in bkmstoreinst.values()]
+ _inhibitmarkers(repo, bkmstorenodes)
+ return orig(bkmstoreinst, *args, **kwargs)
+
+def _bookmark(orig, ui, repo, *bookmarks, **opts):
+ """ Add a -D option to the bookmark command, map it to prune -B """
+ haspruneopt = opts.get('prune', False)
+ if not haspruneopt:
+ return orig(ui, repo, *bookmarks, **opts)
+
+ # Call prune -B
+ evolve = extensions.find('evolve')
+ optsdict = {
+ 'new': [],
+ 'succ': [],
+ 'rev': [],
+ 'bookmark': bookmarks[0],
+ 'keep': None,
+ 'biject': False,
+ }
+ evolve.cmdprune(ui, repo, **optsdict)
+
+# obsolescence inhibitor
+########################
+
+def _schedulewrite(tr, obsinhibit):
+ """Make sure on disk content will be updated on transaction commit"""
+ def writer(fp):
+ """Serialize the inhibited list to disk.
+ """
+ raw = ''.join(obsinhibit)
+ fp.write(raw)
+ tr.addfilegenerator('obsinhibit', ('obsinhibit',), writer)
+ tr.hookargs['obs_inbihited'] = '1'
+
+def _filterpublic(repo, nodes):
+ """filter out inhibitor on public changeset
+
+ Public changesets are already immune to obsolescence"""
+ getrev = repo.changelog.nodemap.get
+ getphase = repo._phasecache.phase
+ return (n for n in repo._obsinhibit
+ if getrev(n) is not None and getphase(repo, getrev(n)))
+
+def _inhibitmarkers(repo, nodes):
+ """add marker inhibitor for all obsolete revision under <nodes>
+
+ Content of <nodes> and all mutable ancestors are considered. Marker for
+ obsolete revision only are created.
+ """
+ newinhibit = repo.set('::%ln and obsolete()', nodes)
+ if newinhibit:
+ lock = tr = None
+ try:
+ lock = repo.lock()
+ tr = repo.transaction('obsinhibit')
+ repo._obsinhibit.update(c.node() for c in newinhibit)
+ _schedulewrite(tr, _filterpublic(repo, repo._obsinhibit))
+ repo.invalidatevolatilesets()
+ tr.close()
+ finally:
+ lockmod.release(tr, lock)
+
+def _deinhibitmarkers(repo, nodes):
+ """lift obsolescence inhibition on a set of nodes
+
+ This will be triggered when inhibited nodes received new obsolescence
+ markers. Otherwise the new obsolescence markers would also be inhibited.
+ """
+ deinhibited = repo._obsinhibit & set(nodes)
+ if deinhibited:
+ tr = repo.transaction('obsinhibit')
+ try:
+ repo._obsinhibit -= deinhibited
+ _schedulewrite(tr, _filterpublic(repo, repo._obsinhibit))
+ repo.invalidatevolatilesets()
+ tr.close()
+ finally:
+ tr.release()
+
+def _createmarkers(orig, repo, relations, flag=0, date=None, metadata=None):
+ """wrap markers create to make sure we de-inhibit target nodes"""
+ # wrapping transactio to unify the one in each function
+ tr = repo.transaction('add-obsolescence-marker')
+ try:
+ orig(repo, relations, flag, date, metadata)
+ precs = (r[0].node() for r in relations)
+ _deinhibitmarkers(repo, precs)
+ tr.close()
+ finally:
+ tr.release()
+
+def transactioncallback(orig, repo, *args, **kwargs):
+ """ Wrap localrepo.transaction to inhibit new obsolete changes """
+ def inhibitposttransaction(transaction):
+ # At the end of the transaction we catch all the new visible and
+ # obsolete commit to inhibit them
+ visibleobsolete = repo.revs('obsolete() - hidden()')
+ ignoreset = set(getattr(repo, '_rebaseset', []))
+ visibleobsolete = list(r for r in visibleobsolete if r not in ignoreset)
+ if visibleobsolete:
+ _inhibitmarkers(repo, [repo[r].node() for r in visibleobsolete])
+ transaction = orig(repo, *args, **kwargs)
+ transaction.addpostclose('inhibitposttransaction', inhibitposttransaction)
+ return transaction
+
+def extsetup(ui):
+ # lets wrap the computation of the obsolete set
+ # We apply inhibition there
+ obsfunc = obsolete.cachefuncs['obsolete']
+ def _computeobsoleteset(repo):
+ """remove any inhibited nodes from the obsolete set
+
+ This will trickle down to other part of mercurial (hidden, log, etc)"""
+ obs = obsfunc(repo)
+ getrev = repo.changelog.nodemap.get
+ for n in repo._obsinhibit:
+ obs.discard(getrev(n))
+ return obs
+ try:
+ extensions.find('directaccess')
+ except KeyError:
+ errormsg = _('Cannot use inhibit without the direct access extension')
+ raise error.Abort(errormsg)
+
+ # Wrapping this to inhibit obsolete revs resulting from a transaction
+ extensions.wrapfunction(localrepo.localrepository,
+ 'transaction', transactioncallback)
+
+ obsolete.cachefuncs['obsolete'] = _computeobsoleteset
+ # wrap create marker to make it able to lift the inhibition
+ extensions.wrapfunction(obsolete, 'createmarkers', _createmarkers)
+ # drop divergence computation since it is incompatible with "light revive"
+ obsolete.cachefuncs['divergent'] = lambda repo: set()
+ # drop bumped computation since it is incompatible with "light revive"
+ obsolete.cachefuncs['bumped'] = lambda repo: set()
+ # wrap update to make sure that no obsolete commit is visible after an
+ # update
+ extensions.wrapcommand(commands.table, 'update', _update)
+ # There are two ways to save bookmark changes during a transation, we
+ # wrap both to add inhibition markers.
+ extensions.wrapfunction(bookmarks.bmstore, 'recordchange', _bookmarkchanged)
+ extensions.wrapfunction(bookmarks.bmstore, 'write', _bookmarkchanged)
+ # Add bookmark -D option
+ entry = extensions.wrapcommand(commands.table, 'bookmark', _bookmark)
+ entry[1].append(('D','prune',None,
+ _('delete the bookmark and prune the commits underneath')))
+
+@command('debugobsinhibit', [], '')
+def cmddebugobsinhibit(ui, repo, *revs):
+ """inhibit obsolescence markers effect on a set of revs"""
+ nodes = (repo[r].node() for r in scmutil.revrange(repo, revs))
+ _inhibitmarkers(repo, nodes)
--- a/hgext/obsolete.py Tue Jun 23 15:32:15 2015 -0700
+++ b/hgext/obsolete.py Tue Jun 23 15:32:47 2015 -0700
@@ -14,8 +14,6 @@
try:
from mercurial import obsolete
- if not obsolete._enabled:
- obsolete._enabled = True
except ImportError:
raise util.Abort('Obsolete extension requires Mercurial 2.3 (or later)')
@@ -40,6 +38,10 @@
"""
if not repo.local():
return
+ evolveopts = ui.configlist('experimental', 'evolution')
+ if not evolveopts:
+ evolveopts = 'all'
+ ui.setconfig('experimental', 'evolution', evolveopts)
for arg in sys.argv:
if 'debugc' in arg:
break
--- a/hgext/pushexperiment.py Tue Jun 23 15:32:15 2015 -0700
+++ b/hgext/pushexperiment.py Tue Jun 23 15:32:47 2015 -0700
@@ -49,7 +49,8 @@
def syncpush(orig, repo, remote):
"""wraper for obsolete.syncpush to use the fast way if possible"""
- if not (obsolete._enabled and repo.obsstore):
+ if not (obsolete.isenabled(repo, obsolete.exchangeopt) and
+ repo.obsstore):
return
if remote.capable('_push_experiment_pushobsmarkers_0'):
return # already pushed before changeset
@@ -75,7 +76,7 @@
"""push wrapped that call the wire protocol command"""
if not remote.canpush():
raise util.Abort(_("destination does not support push"))
- if (obsolete._enabled and repo.obsstore
+ if (obsolete.isenabled(repo, obsolete.exchangeopt) and repo.obsstore
and remote.capable('_push_experiment_pushobsmarkers_0')):
# push marker early to limit damage of pushing too early.
try:
@@ -94,7 +95,7 @@
def capabilities(orig, repo, proto):
"""wrapper to advertise new capability"""
caps = orig(repo, proto)
- if obsolete._enabled:
+ if obsolete.isenabled(repo, obsolete.exchangeopt):
caps += ' _push_experiment_pushobsmarkers_0'
caps += ' _push_experiment_notifypushend_0'
return caps
--- a/hgext/simple4server.py Tue Jun 23 15:32:15 2015 -0700
+++ b/hgext/simple4server.py Tue Jun 23 15:32:47 2015 -0700
@@ -12,7 +12,6 @@
buglink = 'http://bz.selenic.com/'
import mercurial.obsolete
-mercurial.obsolete._enabled = True
import struct
from mercurial import util
@@ -31,8 +30,6 @@
gboptslist = gboptsmap = None
try:
from mercurial import obsolete
- if not obsolete._enabled:
- obsolete._enabled = True
from mercurial import wireproto
gboptslist = getattr(wireproto, 'gboptslist', None)
gboptsmap = getattr(wireproto, 'gboptsmap', None)
@@ -247,7 +244,7 @@
"""wrapper to advertise new capability"""
caps = orig(repo, proto)
advertise = repo.ui.configbool('__temporary__', 'advertiseobsolete', True)
- if obsolete._enabled and advertise:
+ if obsolete.isenabled(repo, obsolete.exchangeopt) and advertise:
caps += ' _evoext_pushobsmarkers_0'
caps += ' _evoext_pullobsmarkers_0'
caps += ' _evoext_obshash_0'
@@ -302,3 +299,8 @@
extensions.wrapfunction(pushkey, '_nslist', _nslist)
pushkey._namespaces['namespaces'] = (lambda *x: False, pushkey._nslist)
+def reposetup(ui, repo):
+ evolveopts = ui.configlist('experimental', 'evolution')
+ if not evolveopts:
+ evolveopts = 'all'
+ ui.setconfig('experimental', 'evolution', evolveopts)
--- a/setup.py Tue Jun 23 15:32:15 2015 -0700
+++ b/setup.py Tue Jun 23 15:32:47 2015 -0700
@@ -1,6 +1,7 @@
# Copied from histedit setup.py
# Credit to Augie Fackler <durin42@gmail.com>
+import os
from distutils.core import setup
from os.path import dirname, join
@@ -14,6 +15,14 @@
if "'" in line:
return line.split("'")[1]
+py_modules = [
+ 'hgext.evolve',
+]
+
+if os.environ.get('INCLUDE_INHIBIT'):
+ py_modules.append('hgext.inhibit')
+ py_modules.append('hgext.directaccess')
+
setup(
name='hg-evolve',
version=get_version('hgext/evolve.py'),
@@ -25,5 +34,5 @@
long_description=open('README').read(),
keywords='hg mercurial',
license='GPLv2+',
- py_modules=['hgext.evolve'],
+ py_modules=py_modules
)
--- a/tests/killdaemons.py Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/killdaemons.py Tue Jun 23 15:32:47 2015 -0700
@@ -1,25 +1,91 @@
#!/usr/bin/env python
-import os, time, errno, signal
+import os, sys, time, errno, signal
+
+if os.name =='nt':
+ import ctypes
+
+ def _check(ret, expectederr=None):
+ if ret == 0:
+ winerrno = ctypes.GetLastError()
+ if winerrno == expectederr:
+ return True
+ raise ctypes.WinError(winerrno)
-# Kill off any leftover daemon processes
-try:
- fp = open(os.environ['DAEMON_PIDS'])
- for line in fp:
+ def kill(pid, logfn, tryhard=True):
+ logfn('# Killing daemon process %d' % pid)
+ PROCESS_TERMINATE = 1
+ PROCESS_QUERY_INFORMATION = 0x400
+ SYNCHRONIZE = 0x00100000
+ WAIT_OBJECT_0 = 0
+ WAIT_TIMEOUT = 258
+ handle = ctypes.windll.kernel32.OpenProcess(
+ PROCESS_TERMINATE|SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
+ False, pid)
+ if handle == 0:
+ _check(0, 87) # err 87 when process not found
+ return # process not found, already finished
try:
- pid = int(line)
- except ValueError:
- continue
+ r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
+ if r == WAIT_OBJECT_0:
+ pass # terminated, but process handle still available
+ elif r == WAIT_TIMEOUT:
+ _check(ctypes.windll.kernel32.TerminateProcess(handle, -1))
+ else:
+ _check(r)
+
+ # TODO?: forcefully kill when timeout
+ # and ?shorter waiting time? when tryhard==True
+ r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
+ # timeout = 100 ms
+ if r == WAIT_OBJECT_0:
+ pass # process is terminated
+ elif r == WAIT_TIMEOUT:
+ logfn('# Daemon process %d is stuck')
+ else:
+ _check(r) # any error
+ except: #re-raises
+ ctypes.windll.kernel32.CloseHandle(handle) # no _check, keep error
+ raise
+ _check(ctypes.windll.kernel32.CloseHandle(handle))
+
+else:
+ def kill(pid, logfn, tryhard=True):
try:
os.kill(pid, 0)
+ logfn('# Killing daemon process %d' % pid)
os.kill(pid, signal.SIGTERM)
- for i in range(10):
- time.sleep(0.05)
+ if tryhard:
+ for i in range(10):
+ time.sleep(0.05)
+ os.kill(pid, 0)
+ else:
+ time.sleep(0.1)
os.kill(pid, 0)
+ logfn('# Daemon process %d is stuck - really killing it' % pid)
os.kill(pid, signal.SIGKILL)
except OSError, err:
if err.errno != errno.ESRCH:
raise
- fp.close()
-except IOError:
- pass
+
+def killdaemons(pidfile, tryhard=True, remove=False, logfn=None):
+ if not logfn:
+ logfn = lambda s: s
+ # Kill off any leftover daemon processes
+ try:
+ fp = open(pidfile)
+ for line in fp:
+ try:
+ pid = int(line)
+ except ValueError:
+ continue
+ kill(pid, logfn, tryhard)
+ fp.close()
+ if remove:
+ os.unlink(pidfile)
+ except IOError:
+ pass
+
+if __name__ == '__main__':
+ path, = sys.argv[1:]
+ killdaemons(path)
--- a/tests/test-amend.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-amend.t Tue Jun 23 15:32:47 2015 -0700
@@ -115,6 +115,7 @@
branch: foo
commit: 1 unknown (clean)
update: (current)
+ phases: 3 draft
Check the help
$ hg amend -h
--- a/tests/test-corrupt.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-corrupt.t Tue Jun 23 15:32:47 2015 -0700
@@ -110,8 +110,7 @@
adding manifests
adding file changes
added 1 changesets with 2 changes to 2 files
- pushing 2 obsolescence markers (* bytes) (glob)
- 2 obsolescence markers added
+ 2 new obsolescence markers
$ hg -R ../other verify
checking changesets
checking manifests
--- a/tests/test-evolve-bumped.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-evolve-bumped.t Tue Jun 23 15:32:47 2015 -0700
@@ -1,6 +1,11 @@
$ hg init public
$ cd public
$ echo a > a
+ $ mkcommit() {
+ > echo "$1" > "$1"
+ > hg add "$1"
+ > hg ci -m "add $1"
+ > }
$ hg commit -A -m init
adding a
$ cd ..
@@ -11,6 +16,8 @@
$ cat >> .hg/hgrc <<EOF
> [extensions]
> evolve = $evolvepath
+ > [ui]
+ > logtemplate = {rev}:{node|short}@{branch}({phase}) {desc|firstline}\n
> [phases]
> publish = false
> EOF
@@ -32,12 +39,7 @@
adding file changes
added 1 changesets with 1 changes to 1 files
$ hg log -r 'draft()'
- changeset: 1:4d1169d82e47
- tag: tip
- user: alice
- date: Thu Jan 01 00:00:00 1970 +0000
- summary: modify a
-
+ 1:4d1169d82e47@default(draft) modify a
$ cd ../bob
$ hg pull ../private
@@ -47,15 +49,9 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pull obsolescence markers
(run 'hg update' to get a working copy)
$ hg log -r 'draft()'
- changeset: 1:4d1169d82e47
- tag: tip
- user: alice
- date: Thu Jan 01 00:00:00 1970 +0000
- summary: modify a
-
+ 1:4d1169d82e47@default(draft) modify a
$ hg push ../public
pushing to ../public
searching for changes
@@ -71,12 +67,59 @@
pulling from ../public
searching for changes
no changes found
- pull obsolescence markers
1 new bumped changesets
- $ hg evolve -a
+ $ hg evolve -a -A --bumped
recreate:[2] tweak a
atop:[1] modify a
computing new diff
committed as 4d1169d82e47
working directory is now at 4d1169d82e47
+
+Bumped Merge changeset:
+-----------------------
+
+We currently cannot automatically solve bumped changeset that is the
+product of a merge, we add a test for it.
+
+ $ mkcommit _a
+ $ hg up .^
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit _b
+ created new head
+ $ mkcommit _c
+ $ hg log -G
+ @ 5:eeaf70969381@default(draft) add _c
+ |
+ o 4:6612fc0ddeb6@default(draft) add _b
+ |
+ | o 3:154ad198ff4a@default(draft) add _a
+ |/
+ o 1:4d1169d82e47@default(public) modify a
+ |
+ o 0:d3873e73d99e@default(public) init
+
+ $ hg merge 3
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m "merge"
+ $ hg commit --amend -m "New message"
+ $ hg phase --public 551127da2a8a --hidden
+ 1 new bumped changesets
+ $ hg log -G
+ @ 7:b28e84916d8c@default(draft) New message
+ |\
+ +---o 6:551127da2a8a@default(public) merge
+ | |/
+ | o 5:eeaf70969381@default(public) add _c
+ | |
+ | o 4:6612fc0ddeb6@default(public) add _b
+ | |
+ o | 3:154ad198ff4a@default(public) add _a
+ |/
+ o 1:4d1169d82e47@default(public) modify a
+ |
+ o 0:d3873e73d99e@default(public) init
+
+ $ hg evolve --all --bumped
+ skipping b28e84916d8c : we do not handle merge yet
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-order.t Tue Jun 23 15:32:47 2015 -0700
@@ -0,0 +1,263 @@
+evolve --rev reordering
+-----------------------
+
+ $ cat >> $HGRCPATH <<EOF
+ > [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]
+ > hgext.graphlog=
+ > EOF
+ $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+ $ mkcommit() {
+ > echo "$1" > "$1"
+ > hg add "$1"
+ > hg ci -m "add $1"
+ > }
+
+ $ mkstack() {
+ > # Creates a stack of commit based on $1 with messages from $2, $3 ..
+ > hg update "$1" -C
+ > shift
+ > mkcommits $*
+ > }
+
+ $ mkcommits() {
+ > for i in $@; do mkcommit $i ; done
+ > }
+
+Initial setup
+ $ hg init testrevorder
+ $ cd testrevorder
+ $ mkcommits p _a _b _c
+ $ hg phase --public 0
+ $ hg up 'desc(_a)'
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo "aaa" > _a
+ $ hg amend
+ 2 new unstable changesets
+ $ hg log -G
+ @ 5:12d519679175@default(draft) add _a
+ |
+ | o 3:4d156641b718@default(draft) add _c
+ | |
+ | o 2:4d7242ebb004@default(draft) add _b
+ | |
+ | x 1:2d73fcd7f07d@default(draft) add _a
+ |/
+ o 0:f92638be10c7@default(public) add p
+
+
+evolve --rev reorders the rev to solve instability, trivial case 2 revs wrong order
+ $ hg evolve --rev 'desc(_c) + desc(_b)'
+ move:[2] add _b
+ atop:[5] add _a
+ move:[3] add _c
+ atop:[6] add _b
+ working directory is now at 52b8f9b04f83
+
+evolve --rev reorders the rev to solve instability. Harder case, obsolescence
+accross three stacks in growing rev numbers.
+ $ hg up "desc(_c)"
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkcommit _d
+ $ hg up "desc(_a)"
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg amend -m "aprime"
+ 3 new unstable changesets
+ $ hg evolve --rev "desc(_b)"
+ move:[6] add _b
+ atop:[9] aprime
+ working directory is now at 476c9c052aae
+ $ hg up "desc(_b) - obsolete()"
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg amend -m "bprime"
+ $ hg up "desc(aprime)"
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg amend -m "asecond"
+ 1 new unstable changesets
+ $ hg log -G
+ @ 12:9a584314f3f3@default(draft) asecond
+ |
+ | o 11:a59c79776f7c@default(draft) bprime
+ | |
+ | x 9:81a687b96d4d@default(draft) aprime
+ |/
+ | o 8:464731bc0ed0@default(draft) add _d
+ | |
+ | o 7:52b8f9b04f83@default(draft) add _c
+ | |
+ | x 6:59476c3836ef@default(draft) add _b
+ | |
+ | x 5:12d519679175@default(draft) add _a
+ |/
+ o 0:f92638be10c7@default(public) add p
+
+ $ hg evolve --rev "unstable()"
+ move:[11] bprime
+ atop:[12] asecond
+ move:[7] add _c
+ atop:[13] bprime
+ move:[8] add _d
+ atop:[14] add _c
+ working directory is now at 225d2cc5d3fc
+ $ hg log -G
+ @ 15:225d2cc5d3fc@default(draft) add _d
+ |
+ o 14:0fc229278e4d@default(draft) add _c
+ |
+ o 13:c3741b9eafae@default(draft) bprime
+ |
+ o 12:9a584314f3f3@default(draft) asecond
+ |
+ o 0:f92638be10c7@default(public) add p
+
+
+Evolve --rev more complex case: two sets of stacks one with prune an no successor, the other one
+partially solvable
+
+First set of stack:
+ $ mkstack "desc(_d)" c1_ c2_ c3_ c4_ >/dev/null
+ $ mkstack "desc(_d)" c1prime c2prime >/dev/null
+ $ mkstack "desc(_d)" c1second >/dev/null
+ $ hg prune "desc(c1_)" -s "desc(c1prime)"
+ 1 changesets pruned
+ 3 new unstable changesets
+ $ hg prune "desc(c2_)" -s "desc(c2prime)"
+ 1 changesets pruned
+ $ hg prune "desc(c1prime)" -s "desc(c1second)"
+ 1 changesets pruned
+ 1 new unstable changesets
+ $ hg log -G -r "desc(_d)::"
+ @ 22:a329855d0bc1@default(draft) add c1second
+ |
+ | o 21:072276ece1bf@default(draft) add c2prime
+ | |
+ | x 20:f137acd06692@default(draft) add c1prime
+ |/
+ | o 19:0a1d9b2ce733@default(draft) add c4_
+ | |
+ | o 18:e2874f41c56c@default(draft) add c3_
+ | |
+ | x 17:3247c33339fa@default(draft) add c2_
+ | |
+ | x 16:df322257c182@default(draft) add c1_
+ |/
+ o 15:225d2cc5d3fc@default(draft) add _d
+ |
+
+Second set of stack with no successor for b2_:
+ $ mkstack "desc(_d)" b1_ b2_ b3_ b4_ >/dev/null
+ $ mkstack "desc(_d)" b1prime b3prime >/dev/null
+ $ hg prune "desc(b1_)" -s "desc(b1prime)"
+ 1 changesets pruned
+ 3 new unstable changesets
+ $ hg prune "desc(b3_)" -s "desc(b3prime)"
+ 1 changesets pruned
+ $ hg prune "desc(b2_)"
+ 1 changesets pruned
+
+ $ hg log -G -r "desc(_d)::"
+ @ 28:ba4c348b6d5e@default(draft) add b3prime
+ |
+ o 27:8fe985f5d0aa@default(draft) add b1prime
+ |
+ | o 26:1d9ba2e75c93@default(draft) add b4_
+ | |
+ | x 25:aec6a9657b6c@default(draft) add b3_
+ | |
+ | x 24:a69b58575918@default(draft) add b2_
+ | |
+ | x 23:3564eb18e448@default(draft) add b1_
+ |/
+ | o 22:a329855d0bc1@default(draft) add c1second
+ |/
+ | o 21:072276ece1bf@default(draft) add c2prime
+ | |
+ | x 20:f137acd06692@default(draft) add c1prime
+ |/
+ | o 19:0a1d9b2ce733@default(draft) add c4_
+ | |
+ | o 18:e2874f41c56c@default(draft) add c3_
+ | |
+ | x 17:3247c33339fa@default(draft) add c2_
+ | |
+ | x 16:df322257c182@default(draft) add c1_
+ |/
+ o 15:225d2cc5d3fc@default(draft) add _d
+ |
+
+Solve the full second stack and only part of the first one
+ $ echo "(desc(_d)::) - desc(c3_)"
+ (desc(_d)::) - desc(c3_)
+ $ hg evolve --rev "(desc(_d)::) - desc(c3_)"
+ cannot solve instability of 0a1d9b2ce733, skipping
+ move:[21] add c2prime
+ atop:[22] add c1second
+ move:[26] add b4_
+ atop:[28] add b3prime
+ working directory is now at 4897c8ed7645
+
+Cleanup
+ $ hg evolve --rev "(desc(_d)::)"
+ move:[18] add c3_
+ atop:[29] add c2prime
+ move:[19] add c4_
+ atop:[31] add c3_
+ working directory is now at 4ee8feb52325
+ $ hg log -G -r "desc(_d)::"
+ @ 32:4ee8feb52325@default(draft) add c4_
+ |
+ o 31:08a530ce67e1@default(draft) add c3_
+ |
+ | o 30:4897c8ed7645@default(draft) add b4_
+ | |
+ o | 29:3abc7618dd5f@default(draft) add c2prime
+ | |
+ | o 28:ba4c348b6d5e@default(draft) add b3prime
+ | |
+ | o 27:8fe985f5d0aa@default(draft) add b1prime
+ | |
+ o | 22:a329855d0bc1@default(draft) add c1second
+ |/
+ o 15:225d2cc5d3fc@default(draft) add _d
+ |
+
+Test multiple revision with some un-evolvable because parent is splitted
+------------------------------------------------------------------------
+
+ $ hg up 'desc(c2prime)'
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit c3part1
+ created new head
+ $ hg prev
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ [29] add c2prime
+ $ mkcommit c3part2
+ created new head
+ $ hg prune -s 'desc(c3part1)' 'desc(c3_)'
+ 1 changesets pruned
+ 1 new unstable changesets
+ $ hg prune -s 'desc(c3part2)' 'desc(c3_)'
+ 1 changesets pruned
+ 2 new divergent changesets
+ $ hg up 'desc(b3prime)'
+ 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg amend -m 'b3second'
+ 1 new unstable changesets
+ $ hg evolve --rev 'unstable()'
+ move:[30] add b4_
+ atop:[35] b3second
+ skipping 08a530ce67e1: divergent rewriting. can't choose destination
+ working directory is now at a51a8a82fdba
+
--- a/tests/test-evolve.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-evolve.t Tue Jun 23 15:32:47 2015 -0700
@@ -22,10 +22,65 @@
> hg ci -m "add $1"
> }
+ $ mkstack() {
+ > # Creates a stack of commit based on $1 with messages from $2, $3 ..
+ > hg update $1 -C
+ > shift
+ > mkcommits $*
+ > }
+
$ glog() {
> hg glog --template '{rev}:{node|short}@{branch}({phase}) {desc|firstline}\n' "$@"
> }
+ $ shaof() {
+ > hg log -T {node} -r "first(desc($1))"
+ > }
+
+ $ mkcommits() {
+ > for i in $@; do mkcommit $i ; done
+ > }
+
+Test the evolution test topic is installed
+
+ $ hg help evolution
+ Safely Rewriting History
+ """"""""""""""""""""""""
+
+ Obsolescence markers make it possible to mark changesets that have been
+ deleted or superset in a new version of the changeset.
+
+ Unlike the previous way of handling such changes, by stripping the old
+ changesets from the repository, obsolescence markers can be propagated
+ between repositories. This allows for a safe and simple way of exchanging
+ mutable history and altering it after the fact. Changeset phases are
+ respected, such that only draft and secret changesets can be altered (see
+ "hg hg phases" for details).
+
+ Obsolescence is tracked using "obsolete markers", a piece of metadata
+ tracking which changesets have been made obsolete, potential successors
+ for a given changeset, the moment the changeset was marked as obsolete,
+ and the user who performed the rewriting operation. The markers are stored
+ separately from standard changeset data can be exchanged without any of
+ the precursor changesets, preventing unnecessary exchange of obsolescence
+ data.
+
+ The complete set of obsolescence markers describes a history of changeset
+ modifications that is orthogonal to the repository history of file
+ modifications. This changeset history allows for detection and automatic
+ resolution of edge cases arising from multiple users rewriting the same
+ part of history concurrently.
+
+ Current feature status
+ ======================
+
+ This feature is still in development. If you see this help, you have
+ enable an extension that turned this feature on.
+
+ Obsolescence markers will be exchanged between repositories that
+ explicitly assert support for the obsolescence feature (this can currently
+ only be done via an extension).
+
various init
$ hg init local
@@ -69,9 +124,9 @@
$ hg id -n
5
$ hg kill .
- 1 changesets pruned
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
working directory now at fbb94e3a0ecf
+ 1 changesets pruned
$ hg qlog
4 - fbb94e3a0ecf add e (draft)
3 - 47d2a3944de8 add d (draft)
@@ -82,9 +137,9 @@
test multiple kill
$ hg kill 4 -r 3
- 2 changesets pruned
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
working directory now at 7c3bad9141dc
+ 2 changesets pruned
$ hg qlog
2 - 4538525df7e2 add c (draft)
1 - 7c3bad9141dc add b (public)
@@ -97,9 +152,9 @@
$ echo 4 > g
$ hg add g
$ hg kill .
- 1 changesets pruned
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
working directory now at 7c3bad9141dc
+ 1 changesets pruned
$ hg st
A g
@@ -317,7 +372,7 @@
|
o 0 : base - test
- $ hg evolve --any --traceback
+ $ hg evolve --any --traceback --bumped
recreate:[8] another feature that rox
atop:[7] another feature (child of ba0ec09b1bab)
computing new diff
@@ -419,7 +474,6 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pull obsolescence markers
$ cd alpha
$ cat << EOF > A
@@ -476,8 +530,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pull obsolescence markers
- 2 obsolescence markers added
+ 2 new obsolescence markers
(run 'hg update' to get a working copy)
$ hg up
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -866,9 +919,20 @@
$ hg up 8
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -G --template '{rev} [{branch}] {desc|firstline}\n'
+ o 10 [default] a1__
+ |
+ | o 9 [mybranch] a3
+ | |
+ | @ 8 [mybranch] a2
+ | |
+ | x 7 [default] a1_
+ |/
+ o 0 [default] a0
+
$ hg evolve
- nothing to evolve here
- (2 troubled changesets, do you want --any ?)
+ nothing to evolve on current working copy parent
+ (2 other unstable in the repository, do you want --any or --rev)
[2]
@@ -887,3 +951,291 @@
working directory is now at f37ed7a60f43
$ ls .hg/bookmarks*
.hg/bookmarks
+
+Possibility to select what trouble to solve first, asking for bumped before
+divergent
+ $ hg up 10
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg revert -r 11 --all
+ reverting a
+ $ hg log -G --template '{rev} [{branch}] {desc|firstline}\n'
+ o 11 [mybranch] a2
+ |
+ @ 10 [default] a1__
+ |
+ | o 9 [mybranch] a3
+ | |
+ | x 8 [mybranch] a2
+ | |
+ | x 7 [default] a1_
+ |/
+ o 0 [default] a0
+
+ $ echo "hello world" > newfile
+ $ hg add newfile
+ $ hg commit -m "add new file bumped" -o 11
+ $ hg phase --public --hidden 11
+ 1 new bumped changesets
+ $ hg glog
+ @ 12 : add new file bumped - test
+ |
+ | o 11 : a2 - test
+ |/
+ o 10 testbookmark: a1__ - test
+ |
+ | o 9 : a3 - test
+ | |
+ | x 8 : a2 - test
+ | |
+ | x 7 : a1_ - test
+ |/
+ o 0 : a0 - test
+
+
+Now we have a bumped and an unstable changeset, we solve the bumped first
+normally the unstable changeset would be solve first
+
+ $ hg glog
+ @ 12 : add new file bumped - test
+ |
+ | o 11 : a2 - test
+ |/
+ o 10 testbookmark: a1__ - test
+ |
+ | o 9 : a3 - test
+ | |
+ | x 8 : a2 - test
+ | |
+ | x 7 : a1_ - test
+ |/
+ o 0 : a0 - test
+
+ $ hg evolve -r 12 --bumped
+ recreate:[12] add new file bumped
+ atop:[11] a2
+ computing new diff
+ committed as d66b1e328488
+ working directory is now at d66b1e328488
+ $ hg evolve --any
+ move:[9] a3
+ atop:[13] bumped update to f37ed7a60f43:
+ working directory is now at 7d2ce5f38f9b
+Check that we can resolve troubles in a revset with more than one commit
+ $ hg up 14 -C
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkcommit gg
+ $ hg up 14
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit gh
+ created new head
+ $ hg up 14
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ printf "newline\nnewline\n" >> a
+ $ hg glog
+ o 16 : add gh - test
+ |
+ | o 15 : add gg - test
+ |/
+ @ 14 : a3 - test
+ |
+ o 13 : bumped update to f37ed7a60f43: - test
+ |
+ o 11 : a2 - test
+ |
+ o 10 testbookmark: a1__ - test
+ |
+ o 0 : a0 - test
+
+ $ hg amend
+ 2 new unstable changesets
+ $ hg glog
+ @ 18 : a3 - test
+ |
+ | o 16 : add gh - test
+ | |
+ | | o 15 : add gg - test
+ | |/
+ | x 14 : a3 - test
+ |/
+ o 13 : bumped update to f37ed7a60f43: - test
+ |
+ o 11 : a2 - test
+ |
+ o 10 testbookmark: a1__ - test
+ |
+ o 0 : a0 - test
+
+
+Evolving an empty revset should do nothing
+ $ hg evolve --rev "16 and 15"
+ set of specified revisions is empty
+ [1]
+
+ $ hg evolve --rev "14::" --bumped
+ no bumped changesets in specified revisions
+ (do you want to use --unstable)
+ [2]
+ $ hg evolve --rev "14::" --unstable
+ move:[15] add gg
+ atop:[18] a3
+ move:[16] add gh
+ atop:[18] a3
+ working directory is now at db3d894869b0
+ $ hg glog
+ @ 20 : add gh - test
+ |
+ | o 19 : add gg - test
+ |/
+ o 18 : a3 - test
+ |
+ o 13 : bumped update to f37ed7a60f43: - test
+ |
+ o 11 : a2 - test
+ |
+ o 10 testbookmark: a1__ - test
+ |
+ o 0 : a0 - test
+
+Check hg evolve --rev on singled out commit
+
+
+ $ hg up 19 -C
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit j1
+ $ mkcommit j2
+ $ mkcommit j3
+ $ hg up .^^
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ echo "hello" > j4
+ $ hg add j4
+ $ hg amend
+ 2 new unstable changesets
+ $ glog -r "18::"
+ @ 25:4c0bc042ef3b@default(draft) add j1
+ |
+ | o 23:c70048fd3350@default(draft) add j3
+ | |
+ | o 22:714e60ca57b7@default(draft) add j2
+ | |
+ | x 21:b430835af718@default(draft) add j1
+ |/
+ | o 20:db3d894869b0@default(draft) add gh
+ | |
+ o | 19:10ffdd7e3cc9@default(draft) add gg
+ |/
+ o 18:0bb66d4c1968@default(draft) a3
+ |
+
+ $ hg evolve --rev 23 --any
+ abort: cannot specify both "--rev" and "--any"
+ [255]
+ $ hg evolve --rev 23
+ cannot solve instability of c70048fd3350, skipping
+
+Check that uncommit respects the allowunstable option
+With only createmarkers we can only uncommit on a head
+ $ cat >> $HGRCPATH <<EOF
+ > [experimental]
+ > evolution=createmarkers, allnewcommands
+ > EOF
+ $ hg up 4c0bc042ef3b^
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg uncommit --all
+ abort: cannot uncommit in the middle of a stack
+ [255]
+ $ hg up 4c0bc042ef3b
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg uncommit --all
+ new changeset is empty
+ (use "hg prune ." to remove it)
+ $ glog -r "18::"
+ @ 26:04b32348803e@default(draft) add j1
+ |
+ | o 23:c70048fd3350@default(draft) add j3
+ | |
+ | o 22:714e60ca57b7@default(draft) add j2
+ | |
+ | x 21:b430835af718@default(draft) add j1
+ |/
+ | o 20:db3d894869b0@default(draft) add gh
+ | |
+ o | 19:10ffdd7e3cc9@default(draft) add gg
+ |/
+ o 18:0bb66d4c1968@default(draft) a3
+ |
+
+Check that prune respects the allowunstable option
+ $ hg up -C .
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg up 20
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg evolve --all
+ nothing to evolve on current working copy parent
+ (2 other unstable in the repository, do you want --any or --rev)
+ [2]
+ $ hg evolve --all --any
+ move:[22] add j2
+ atop:[26] add j1
+ move:[23] add j3
+ atop:[27] add j2
+ working directory is now at 920a35e8dbd0
+ $ glog -r "18::"
+ @ 28:920a35e8dbd0@default(draft) add j3
+ |
+ o 27:31e050d895dd@default(draft) add j2
+ |
+ o 26:04b32348803e@default(draft) add j1
+ |
+ | o 20:db3d894869b0@default(draft) add gh
+ | |
+ o | 19:10ffdd7e3cc9@default(draft) add gg
+ |/
+ o 18:0bb66d4c1968@default(draft) a3
+ |
+ $ hg up 19
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit c5_
+ created new head
+ $ hg prune '26 + 27'
+ abort: cannot prune in the middle of a stack
+ [255]
+ $ hg prune '19::28'
+ abort: cannot prune in the middle of a stack
+ [255]
+ $ hg prune '26::'
+ 3 changesets pruned
+ $ glog -r "18::"
+ @ 29:5a6c53544778@default(draft) add c5_
+ |
+ | o 20:db3d894869b0@default(draft) add gh
+ | |
+ o | 19:10ffdd7e3cc9@default(draft) add gg
+ |/
+ o 18:0bb66d4c1968@default(draft) a3
+ |
+
+Check that fold respects the allowunstable option
+ $ hg up 0bb66d4c1968
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ mkcommit unstableifparentisfolded
+ created new head
+ $ glog -r "18::"
+ @ 30:30ecefd67c0a@default(draft) add unstableifparentisfolded
+ |
+ | o 29:5a6c53544778@default(draft) add c5_
+ | |
+ +---o 20:db3d894869b0@default(draft) add gh
+ | |
+ | o 19:10ffdd7e3cc9@default(draft) add gg
+ |/
+ o 18:0bb66d4c1968@default(draft) a3
+ |
+
+ $ hg fold --exact "19 + 18"
+ abort: cannot fold chain not ending with a head or with branching
+ [255]
+ $ hg fold --exact "18::29"
+ abort: cannot fold chain not ending with a head or with branching
+ [255]
+ $ hg fold --exact "19::"
+ 2 changesets folded
--- a/tests/test-exchange-D2.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-exchange-D2.t Tue Jun 23 15:32:47 2015 -0700
@@ -37,9 +37,9 @@
created new head
$ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
$ hg prune --date '0 0' .
- 1 changesets pruned
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
working directory now at a9bdc8b26820
+ 1 changesets pruned
$ hg strip --hidden -q 'desc(A1)'
$ hg log -G --hidden
x 28b51eb45704 (draft): A0
--- a/tests/test-exchange-D3.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-exchange-D3.t Tue Jun 23 15:32:47 2015 -0700
@@ -39,9 +39,9 @@
$ mkcommit A1
$ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(A1)'`
$ hg prune -d '0 0' .
- 1 changesets pruned
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
working directory now at 35b183996678
+ 1 changesets pruned
$ hg strip --hidden -q 'desc(A1)'
$ hg log -G --hidden
@ 35b183996678 (draft): B
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-inhibit.t Tue Jun 23 15:32:47 2015 -0700
@@ -0,0 +1,757 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [ui]
+ > logtemplate = {rev}:{node|short} {desc}\n
+ > [experimental]
+ > prunestrip=True
+ > evolution=createmarkers
+ > [extensions]
+ > rebase=
+ > strip=
+ > EOF
+ $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+ $ echo "directaccess=$(echo $(dirname $TESTDIR))/hgext/directaccess.py" >> $HGRCPATH
+ $ echo "inhibit=$(echo $(dirname $TESTDIR))/hgext/inhibit.py" >> $HGRCPATH
+ $ mkcommit() {
+ > echo "$1" > "$1"
+ > hg add "$1"
+ > hg ci -m "add $1"
+ > }
+
+ $ hg init inhibit
+ $ cd inhibit
+ $ mkcommit cA
+ $ mkcommit cB
+ $ mkcommit cC
+ $ mkcommit cD
+ $ hg up 'desc(cA)'
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ mkcommit cE
+ created new head
+ $ mkcommit cG
+ $ mkcommit cH
+ $ mkcommit cJ
+ $ hg log -G
+ @ 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 3:2db36d8066ff add cD
+ | |
+ | o 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+
+plain prune
+
+ $ hg strip 1::
+ 3 changesets pruned
+ $ hg log -G
+ @ 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg debugobsinhibit --hidden 1::
+ $ hg log -G
+ @ 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 3:2db36d8066ff add cD
+ | |
+ | o 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+ $ hg strip --hidden 1::
+ 3 changesets pruned
+ $ hg log -G
+ @ 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+
+after amend
+
+ $ echo babar > cJ
+ $ hg commit --amend
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg debugobsinhibit --hidden 18214586bf78
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+
+and no divergence
+
+ $ hg summary
+ parent: 9:55c73a90e4b4 tip
+ add cJ
+ branch: default
+ commit: (clean)
+ update: 1 new changesets, 2 branch heads (merge)
+ phases: 6 draft
+
+check public revision got cleared
+(when adding the second inhibitor, the first one is removed because it is public)
+
+ $ wc -m .hg/store/obsinhibit | sed -e 's/^[ \t]*//'
+ 20 .hg/store/obsinhibit
+ $ hg strip 7
+ 1 changesets pruned
+ $ hg debugobsinhibit --hidden 18214586bf78
+ $ wc -m .hg/store/obsinhibit | sed -e 's/^[ \t]*//'
+ 20 .hg/store/obsinhibit
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg phase --public 7
+ $ hg strip 9
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ working directory now at cf5c4f4554ce
+ 1 changesets pruned
+ $ hg log -G
+ o 7:18214586bf78 add cJ
+ |
+ @ 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg debugobsinhibit --hidden 55c73a90e4b4
+ $ wc -m .hg/store/obsinhibit | sed -e 's/^[ \t]*//'
+ 20 .hg/store/obsinhibit
+ $ hg log -G
+ o 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ @ 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+Update should inhibit all related unstable commits
+
+ $ hg update 2 --hidden
+ 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg log -G
+ o 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | @ 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+
+ $ hg update 9
+ 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+ $ hg strip --hidden 1::
+ 3 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+
+Bookmark should inhibit all related unstable commits
+ $ hg bookmark -r 2 book1 --hidden
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+
+Removing a bookmark with bookmark -D should prune the changes underneath
+that are not reachable from another bookmark or head
+
+ $ hg bookmark -r 1 book2
+ $ hg bookmark -D book1 --config experimental.evolution=createmarkers #--config to make sure prune is not registered as a command.
+ bookmark 'book1' deleted
+ 1 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+ $ hg bookmark -D book2
+ bookmark 'book2' deleted
+ 1 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+Test that direct access make changesets visible
+
+ $ hg export 2db36d8066ff 02bcbc3f6e56
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Node ID 2db36d8066ff50e8be3d3e6c2da1ebc0a8381d82
+ # Parent 7df62a38b9bf9daf968de235043ba88a8ef43393
+ add cD
+
+ diff -r 7df62a38b9bf -r 2db36d8066ff cD
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/cD Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +cD
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Node ID 02bcbc3f6e56fb2928efec2c6e24472720bf5511
+ # Parent 54ccbc537fc2d6845a5d61337c1cfb80d1d2815e
+ add cB
+
+ diff -r 54ccbc537fc2 -r 02bcbc3f6e56 cB
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/cB Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +cB
+
+But only with hash
+
+ $ hg export 2db36d8066ff::
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Node ID 2db36d8066ff50e8be3d3e6c2da1ebc0a8381d82
+ # Parent 7df62a38b9bf9daf968de235043ba88a8ef43393
+ add cD
+
+ diff -r 7df62a38b9bf -r 2db36d8066ff cD
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/cD Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +cD
+
+ $ hg export 1 3
+ abort: hidden revision '1'!
+ (use --hidden to access hidden revisions)
+ [255]
+
+
+With severals hidden sha, rebase of one hidden stack onto another one:
+ $ hg update -C 0
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ $ mkcommit cK
+ created new head
+ $ mkcommit cL
+ $ hg update -C 9
+ 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg log -G
+ o 11:53a94305e133 add cL
+ |
+ o 10:ad78ff7d621f add cK
+ |
+ | @ 9:55c73a90e4b4 add cJ
+ | |
+ | | o 7:18214586bf78 add cJ
+ | |/
+ | o 6:cf5c4f4554ce add cH
+ | |
+ | o 5:5419eb264a33 add cG
+ | |
+ | o 4:98065434e5c6 add cE
+ |/
+ o 0:54ccbc537fc2 add cA
+
+ $ hg strip --hidden 10:
+ 2 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg rebase -s 10 -d 3
+ abort: hidden revision '3'!
+ (use --hidden to access hidden revisions)
+ [255]
+ $ hg rebase -r ad78ff7d621f -r 53a94305e133 -d 2db36d8066ff
+ Warning: accessing hidden changesets 2db36d8066ff for write operation
+ Warning: accessing hidden changesets ad78ff7d621f for write operation
+ Warning: accessing hidden changesets 53a94305e133 for write operation
+ rebasing 10:ad78ff7d621f "add cK"
+ rebasing 11:53a94305e133 "add cL"
+ $ hg log -G
+ o 13:2f7b7704d714 add cL
+ |
+ o 12:fe1634cbe235 add cK
+ |
+ | @ 9:55c73a90e4b4 add cJ
+ | |
+ | | o 7:18214586bf78 add cJ
+ | |/
+ | o 6:cf5c4f4554ce add cH
+ | |
+ | o 5:5419eb264a33 add cG
+ | |
+ | o 4:98065434e5c6 add cE
+ | |
+ o | 3:2db36d8066ff add cD
+ | |
+ o | 2:7df62a38b9bf add cC
+ | |
+ o | 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+Check that amending in the middle of a stack does not show obsolete revs
+Since we are doing operation in the middle of the stack we cannot just
+have createmarkers as we are creating instability
+
+ $ cat >> $HGRCPATH <<EOF
+ > [experimental]
+ > evolution=all
+ > EOF
+
+ $ hg strip --hidden 1::
+ 5 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg up 7
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkcommit cL
+ $ mkcommit cM
+ $ mkcommit cN
+ $ hg log -G
+ @ 16:a438c045eb37 add cN
+ |
+ o 15:2d66e189f5b5 add cM
+ |
+ o 14:d66ccb8c5871 add cL
+ |
+ | o 9:55c73a90e4b4 add cJ
+ | |
+ o | 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg up 15
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo "mmm" >> cM
+ $ hg amend
+ $ hg log -G
+ @ 18:210589181b14 add cM
+ |
+ | o 16:a438c045eb37 add cN
+ | |
+ | o 15:2d66e189f5b5 add cM
+ |/
+ o 14:d66ccb8c5871 add cL
+ |
+ | o 9:55c73a90e4b4 add cJ
+ | |
+ o | 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+Check that rebasing a commit twice makes the commit visible again
+
+ $ hg rebase -d 18 -r 16 --keep
+ rebasing 16:a438c045eb37 "add cN"
+ $ hg log -r 14:: -G
+ o 19:104eed5354c7 add cN
+ |
+ @ 18:210589181b14 add cM
+ |
+ | o 16:a438c045eb37 add cN
+ | |
+ | o 15:2d66e189f5b5 add cM
+ |/
+ o 14:d66ccb8c5871 add cL
+ |
+ $ hg strip -r 104eed5354c7
+ 1 changesets pruned
+ $ hg rebase -d 18 -r 16 --keep
+ rebasing 16:a438c045eb37 "add cN"
+ $ hg log -r 14:: -G
+ o 19:104eed5354c7 add cN
+ |
+ @ 18:210589181b14 add cM
+ |
+ | o 16:a438c045eb37 add cN
+ | |
+ | o 15:2d66e189f5b5 add cM
+ |/
+ o 14:d66ccb8c5871 add cL
+ |
+
+Test prunestrip
+
+ $ hg book foo -r 104eed5354c7
+ $ hg strip -r 210589181b14
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ working directory now at d66ccb8c5871
+ 2 changesets pruned
+ $ hg log -r 14:: -G -T '{rev}:{node|short} {desc|firstline} {bookmarks}\n'
+ o 16:a438c045eb37 add cN
+ |
+ o 15:2d66e189f5b5 add cM
+ |
+ @ 14:d66ccb8c5871 add cL foo
+ |
+
+Check that --hidden used with inhibit does not hide every obsolete commit
+We show the log before and after a log -G --hidden, they should be the same
+ $ hg log -G
+ o 16:a438c045eb37 add cN
+ |
+ o 15:2d66e189f5b5 add cM
+ |
+ @ 14:d66ccb8c5871 add cL
+ |
+ | o 9:55c73a90e4b4 add cJ
+ | |
+ o | 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg log -G --hidden
+ x 19:104eed5354c7 add cN
+ |
+ x 18:210589181b14 add cM
+ |
+ | x 17:b3c3274523f9 temporary amend commit for 2d66e189f5b5
+ | |
+ | | o 16:a438c045eb37 add cN
+ | |/
+ | o 15:2d66e189f5b5 add cM
+ |/
+ @ 14:d66ccb8c5871 add cL
+ |
+ | x 13:2f7b7704d714 add cL
+ | |
+ | x 12:fe1634cbe235 add cK
+ | |
+ | | x 11:53a94305e133 add cL
+ | | |
+ | | x 10:ad78ff7d621f add cK
+ | | |
+ | | | o 9:55c73a90e4b4 add cJ
+ | | | |
+ +-------x 8:e84f73d9ad36 temporary amend commit for 18214586bf78
+ | | | |
+ o-----+ 7:18214586bf78 add cJ
+ / / /
+ | | o 6:cf5c4f4554ce add cH
+ | | |
+ | | o 5:5419eb264a33 add cG
+ | | |
+ | | o 4:98065434e5c6 add cE
+ | |/
+ x | 3:2db36d8066ff add cD
+ | |
+ x | 2:7df62a38b9bf add cC
+ | |
+ x | 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+
+ $ hg log -G
+ o 16:a438c045eb37 add cN
+ |
+ o 15:2d66e189f5b5 add cM
+ |
+ @ 14:d66ccb8c5871 add cL
+ |
+ | o 9:55c73a90e4b4 add cJ
+ | |
+ o | 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+
+check that pruning and inhibited node does not confuse anything
+
+ $ hg up --hidden 210589181b14
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg strip --bundle 210589181b14
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/inhibit/.hg/strip-backup/210589181b14-e09c7b88-backup.hg (glob)
+ $ hg unbundle .hg/strip-backup/210589181b14-e09c7b88-backup.hg # restore state
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 1 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ Only allow direct access and check that evolve works like before
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > inhibit=!
+ > EOF
+
+ $ hg up 15
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ working directory parent is obsolete!
+ $ echo "CM" > cM
+ $ hg amend
+ $ hg log -G
+ @ 21:721c3c279519 add cM
+ |
+ | o 16:a438c045eb37 add cN
+ | |
+ | x 15:2d66e189f5b5 add cM
+ |/
+ o 14:d66ccb8c5871 add cL
+ |
+ o 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > EOF
+ $ echo "inhibit=$(echo $(dirname $TESTDIR))/hgext/inhibit.py" >> $HGRCPATH
+
+Empty commit
+ $ hg amend
+ nothing changed
+ [1]
+
+Directaccess should load after some extensions precised in the conf
+With no extension specified:
+
+ $ cat >$TESTTMP/test_extension.py << EOF
+ > from mercurial import extensions
+ > def uisetup(ui):
+ > print extensions._order
+ > EOF
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > testextension=$TESTTMP/test_extension.py
+ > EOF
+ $ hg id
+ ['rebase', 'strip', 'evolve', 'directaccess', 'inhibit', 'testextension']
+ 721c3c279519 tip
+
+With test_extension specified:
+ $ cat >> $HGRCPATH << EOF
+ > [directaccess]
+ > loadsafter=testextension
+ > EOF
+ $ hg id
+ ['rebase', 'strip', 'evolve', 'inhibit', 'testextension', 'directaccess']
+ 721c3c279519 tip
+
+Inhibit should not work without directaccess
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > directaccess=!
+ > testextension=!
+ > EOF
+ $ hg up 15
+ abort: Cannot use inhibit without the direct access extension
+ [255]
+ $ echo "directaccess=$(echo $(dirname $TESTDIR))/hgext/directaccess.py" >> $HGRCPATH
+ $ cd ..
+
+
+hg push should not allow directaccess unless forced with --hidden
+We copy the inhibhit repo to inhibit2 and make some changes to push to inhibit
+
+ $ cp -r inhibit inhibit2
+ $ pwd=$(pwd)
+ $ cd inhibit
+ $ mkcommit pk
+ $ hg id
+ 003a4735afde tip
+ $ echo "OO" > pk
+ $ hg amend
+ $ hg id
+ 71eb4f100663 tip
+
+Hidden commits cannot be pushed without --hidden
+ $ hg push -r 003a4735afde file://$pwd/inhibit2
+ pushing to file://$TESTTMP/inhibit2
+ abort: hidden revision '003a4735afde'!
+ (use --hidden to access hidden revisions)
+ [255]
+
+Visible commits can still be pushed
+ $ hg push -r 71eb4f100663 file://$pwd/inhibit2
+ pushing to file://$TESTTMP/inhibit2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ 2 new obsolescence markers
--- a/tests/test-obsolete.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-obsolete.t Tue Jun 23 15:32:47 2015 -0700
@@ -183,8 +183,7 @@
adding manifests
adding file changes
added 5 changesets with 5 changes to 5 files (+1 heads)
- pushing 2 obsolescence markers (* bytes) (glob)
- 2 obsolescence markers added
+ 2 new obsolescence markers
$ hg -R ../other-new verify
checking changesets
checking manifests
@@ -238,8 +237,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pushing 3 obsolescence markers (* bytes) (glob)
- 1 obsolescence markers added
+ 1 new obsolescence markers
$ qlog -R ../other-new
5
- 95de7fc6918d
@@ -261,8 +259,6 @@
pushing to ../other-new
searching for changes
no changes found
- pushing 3 obsolescence markers (* bytes) (glob)
- 0 obsolescence markers added
[1]
$ hg up --hidden -q .^ # 3
@@ -278,9 +274,8 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
- pull obsolescence markers
- 1 obsolescence markers added
- (run 'hg heads' to see heads, 'hg merge' to merge)
+ 1 new obsolescence markers
+ (run 'hg heads .' to see heads, 'hg merge' to merge)
$ qlog -R ../other-new
6
- 909a0fb57e5d
@@ -369,9 +364,8 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
- pull obsolescence markers
- 1 obsolescence markers added
- (run 'hg heads' to see heads, 'hg merge' to merge)
+ 1 new obsolescence markers
+ (run 'hg heads .' to see heads, 'hg merge' to merge)
$ hg up -q 7 # to check rollback update behavior
$ qlog
@@ -394,6 +388,7 @@
branch: default
commit: 1 deleted, 2 unknown (clean)
update: 2 new changesets, 2 branch heads (merge)
+ phases: 4 draft
unstable: 1 changesets
$ qlog
6
@@ -543,8 +538,7 @@
adding manifests
adding file changes
added 2 changesets with 1 changes to [12] files (re)
- pushing 7 obsolescence markers (* bytes) (glob)
- 3 obsolescence markers added
+ 3 new obsolescence markers
$ hg up -q 10
$ mkcommit "obsol_d'''"
created new head
@@ -556,8 +550,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pushing 8 obsolescence markers (* bytes) (glob)
- 1 obsolescence markers added
+ 1 new obsolescence markers
$ cd ..
check bumped detection
@@ -669,6 +662,7 @@
branch: default
commit: (clean)
update: (2|9|11) new changesets, (3|9|10) branch heads \(merge\) (re)
+ phases: 3 draft
bumped: 1 changesets
$ hg debugobsolete `getid a7a6f2b5d8a5` `getid 50f11e5e3a63`
$ hg log -r 'divergent()'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-options.t Tue Jun 23 15:32:47 2015 -0700
@@ -0,0 +1,30 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [ui]
+ > logtemplate={rev}:{node|short}[{bookmarks}] ({obsolete}/{phase}) {desc|firstline}\n
+ > [extensions]
+ > EOF
+ $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+
+ $ mkcommit() {
+ > echo "$1" > "$1"
+ > hg add "$1"
+ > hg ci -m "add $1"
+ > }
+
+ $ hg init repo
+ $ cd repo
+ $ mkcommit a
+ $ mkcommit b
+
+test disabling commands
+
+ $ cat >> .hg/hgrc <<EOF
+ > [experimental]
+ > evolution=createmarkers
+ > allowunstable
+ > exchange
+ > EOF
+ $ hg prune | head -n 2
+ hg: unknown command 'prune'
+ Mercurial Distributed SCM
+
--- a/tests/test-prune.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-prune.t Tue Jun 23 15:32:47 2015 -0700
@@ -38,9 +38,9 @@
prune current and tip changeset
$ hg prune --user blah --date '1979-12-15' .
- 1 changesets pruned
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
working directory now at 47d2a3944de8
+ 1 changesets pruned
$ hg bookmark
* BABAR 3:47d2a3944de8
$ hg debugobsolete
@@ -59,9 +59,9 @@
pruning multiple changeset at once
$ hg prune 2:
- 2 changesets pruned
0 files updated, 0 files merged, 3 files removed, 0 files unresolved
working directory now at 1f0dee641bb7
+ 2 changesets pruned
$ hg debugobsolete
9d206ffc875e1bc304590549be293be36821e66c 0 {47d2a3944de8b013de3be9578e8e344ea2e6c097} (Sat Dec 15 00:00:00 1979 +0000) {'user': 'blah'}
7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {1f0dee641bb7258c56bd60e93edfa2405381c41e} (*) {'user': 'test'} (glob)
@@ -120,9 +120,9 @@
$ hg up 'desc("add ee")'
4 files updated, 0 files merged, 4 files removed, 0 files unresolved
$ hg prune 'desc("add ee")' -s 'desc("add nE")'
- 1 changesets pruned
4 files updated, 0 files merged, 4 files removed, 0 files unresolved
working directory now at 6e8148413dd5
+ 1 changesets pruned
$ hg debugobsolete
9d206ffc875e1bc304590549be293be36821e66c 0 {47d2a3944de8b013de3be9578e8e344ea2e6c097} (Sat Dec 15 00:00:00 1979 +0000) {'user': 'blah'}
7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {1f0dee641bb7258c56bd60e93edfa2405381c41e} (*) {'user': 'test'} (glob)
@@ -210,9 +210,9 @@
$ mkcommit n2
$ hg prune 'desc("add n1")::desc("add n2")' -s 'desc("add nD")::desc("add nE")' --biject
- 2 changesets pruned
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
working directory now at 1f0dee641bb7
+ 2 changesets pruned
$ hg debugobsolete
9d206ffc875e1bc304590549be293be36821e66c 0 {47d2a3944de8b013de3be9578e8e344ea2e6c097} (Sat Dec 15 00:00:00 1979 +0000) {'user': 'blah'}
7c3bad9141dcb46ff89abf5f61856facd56e476c 0 {1f0dee641bb7258c56bd60e93edfa2405381c41e} (*) {'user': 'test'} (glob)
@@ -225,6 +225,35 @@
cb7f8f706a6532967b98cf8583a81baab79a0fa7 8ee176ff1d4b2034ce51e3efc579c2de346b631d 0 (*) {'user': 'test'} (glob)
21b6f2f1cece8c10326e575dd38239189d467190 6e8148413dd541855b72a920a90c06fca127c7e7 0 (*) {'user': 'test'} (glob)
+test hg strip replacement
+
+ $ hg up 10
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkcommit n1
+ created new head
+ $ mkcommit n2
+ $ hg --config extensions.strip= --config experimental.prunestrip=True strip -r .
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ working directory now at c7e58696a948
+ 1 changesets pruned
+ $ hg --config extensions.strip= --config experimental.prunestrip=True strip -r . --bundle
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/repo/.hg/strip-backup/c7e58696a948-69ca36d3-backup.hg (glob)
+
+test hg prune --keep
+ $ mkcommit n1
+ created new head
+ $ hg diff -r .^
+ diff -r aa96dc3f04c2 n1
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/n1 * +0000 (glob)
+ @@ -0,0 +1,1 @@
+ +n1
+ $ hg prune -r . --keep
+ 1 changesets pruned
+ $ hg status
+ ? n1
+
test hg prune -B bookmark
yoinked from test-mq-strip.t
@@ -245,11 +274,11 @@
[255]
$ hg tag --remove --local a
$ hg prune -B todelete
- 1 changesets pruned
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
(leaving bookmark todelete)
working directory now at d62d843c9a01
bookmark 'todelete' deleted
+ 1 changesets pruned
$ hg id -ir dcbb326fdec2
abort: hidden revision 'dcbb326fdec2'!
(use --hidden to access hidden revisions)
@@ -260,8 +289,8 @@
B 10:ff43616e5d0f
delete 6:2702dd0c91e7
$ hg prune -B delete
+ bookmark 'delete' deleted
3 changesets pruned
- bookmark 'delete' deleted
$ hg tag --remove --local c
$ hg id -ir 6:2702dd0c91e7
abort: hidden revision '6'!
@@ -332,3 +361,12 @@
|/
o 0:1ea73414a91b[] (stable/draft) r0
+ $ hg book CELESTE
+ $ hg prune -r . --keep
+ 1 changesets pruned
+ $ hg book
+ B 8:d62d843c9a01
+ * CELESTE 8:d62d843c9a01
+ r10 8:d62d843c9a01
+ rg 8:d62d843c9a01
+
--- a/tests/test-sharing.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-sharing.t Tue Jun 23 15:32:47 2015 -0700
@@ -46,7 +46,6 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pull obsolescence markers
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
Let's commit a preliminary change and push it to ``test-repo`` for
@@ -88,8 +87,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pull obsolescence markers
- 2 obsolescence markers added
+ 2 new obsolescence markers
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
Figure SG03
@@ -140,8 +138,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pushing 4 obsolescence markers (* bytes) (glob)
- 4 obsolescence markers added
+ 4 new obsolescence markers
Now that the fix is public, we cannot amend it any more.
$ hg amend -m 'fix bug 37'
@@ -161,8 +158,6 @@
pushing to ../dev-repo
searching for changes
no changes found
- pushing 4 obsolescence markers (* bytes) (glob)
- 0 obsolescence markers added
[1]
$ hg -R ../dev-repo shortlog -r 'draft()'
@@ -196,8 +191,6 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pushing 4 obsolescence markers (* bytes) (glob)
- 0 obsolescence markers added
exporting bookmark bug15
$ hg -R ../review bookmarks
bug15 2:f91e97234c2b
@@ -213,8 +206,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pushing 6 obsolescence markers (* bytes) (glob)
- 2 obsolescence markers added
+ 2 new obsolescence markers
updating bookmark bug15
$ hg -R ../review bookmarks
bug15 3:cbdfbd5a5db2
@@ -241,8 +233,6 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pushing 4 obsolescence markers (* bytes) (glob)
- 0 obsolescence markers added
exporting bookmark featureX
$ hg -R ../review bookmarks
bug15 3:cbdfbd5a5db2
@@ -259,8 +249,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pushing 6 obsolescence markers (* bytes) (glob)
- 2 obsolescence markers added
+ 2 new obsolescence markers
updating bookmark featureX
Bob receives second review, amends, and pushes to public:
@@ -274,8 +263,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pushing 8 obsolescence markers (* bytes) (glob)
- 4 obsolescence markers added
+ 4 new obsolescence markers
$ hg -R ../public bookmarks
no bookmarks set
$ hg push ../review
@@ -286,8 +274,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pushing 8 obsolescence markers (* bytes) (glob)
- 2 obsolescence markers added
+ 2 new obsolescence markers
updating bookmark featureX
$ hg -R ../review bookmarks
bug15 3:cbdfbd5a5db2
@@ -357,8 +344,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pull obsolescence markers
- 4 obsolescence markers added
+ 4 new obsolescence markers
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg log -G -q -r 'head()'
o 5:540ba8f317e6
@@ -388,8 +374,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pushing 11 obsolescence markers (* bytes) (glob)
- 3 obsolescence markers added
+ 3 new obsolescence markers
$ hg push ../review
pushing to ../review
searching for changes
@@ -397,8 +382,7 @@
adding manifests
adding file changes
added 1 changesets with 0 changes to 1 files
- pushing 11 obsolescence markers (* bytes) (glob)
- 1 obsolescence markers added
+ 1 new obsolescence markers
updating bookmark bug15
Figure SG08: review and public changesets after Alice pushes.
@@ -460,8 +444,6 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pull obsolescence markers
- 0 obsolescence markers added
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ echo 'better fix (alice)' >> file1
$ hg amend -u alice -m 'fix bug 24 (v2 by alice)'
@@ -489,8 +471,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pull obsolescence markers
- 2 obsolescence markers added
+ 2 new obsolescence markers
(run 'hg heads' to see heads, 'hg merge' to merge)
2 new divergent changesets
@@ -511,7 +492,7 @@
7:e3f99ce9d9cd draft fix bug 24 (v2 by alice)
Use evolve to fix the divergence.
- $ HGMERGE=internal:other hg evolve
+ $ HGMERGE=internal:other hg evolve --divergent
merge:[6] fix bug 24 (v2 by bob)
with: [7] fix bug 24 (v2 by alice)
base: [4] fix bug 24 (v1)
--- a/tests/test-simple4server-bundle2.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-simple4server-bundle2.t Tue Jun 23 15:32:47 2015 -0700
@@ -72,9 +72,9 @@
===================
$ wget -q -O - http://localhost:$HGPORT/?cmd=hello
- capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon
+ capabilities: * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (glob)
$ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities
- lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol)
+ * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol) (glob)
$ wget -q -O - "http://localhost:$HGPORT/?cmd=listkeys&namespace=namespaces" | sort
bookmarks
@@ -134,13 +134,13 @@
obsolete
phases
$ wget -q -O - http://localhost:$HGPORT/?cmd=hello
- capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon
+ capabilities: * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (glob)
$ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities
- lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol)
+ * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol) (glob)
$ echo '[__temporary__]' >> server/.hg/hgrc
$ echo 'advertiseobsolete=False' >> server/.hg/hgrc
- $ $TESTDIR/killdaemons.py
+ $ $TESTDIR/killdaemons.py $DAEMON_PIDS
$ hg serve -R server -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
@@ -148,13 +148,9 @@
bookmarks
namespaces
phases
- $ wget -q -O - http://localhost:$HGPORT/?cmd=hello
- capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
- $ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities
- lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 (no-eol)
$ echo 'advertiseobsolete=True' >> server/.hg/hgrc
- $ $TESTDIR/killdaemons.py
+ $ $TESTDIR/killdaemons.py $DAEMON_PIDS
$ hg serve -R server -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
@@ -163,7 +159,8 @@
namespaces
obsolete
phases
+
$ wget -q -O - http://localhost:$HGPORT/?cmd=hello
- capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon
+ capabilities: * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (glob)
$ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities
- lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol)
+ * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol) (glob)
--- a/tests/test-simple4server.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-simple4server.t Tue Jun 23 15:32:47 2015 -0700
@@ -7,6 +7,8 @@
> allow_push = *
> [phases]
> publish = False
+ > [experimental]
+ > bundle2-exp=False
> [extensions]
> EOF
@@ -72,9 +74,9 @@
===================
$ wget -q -O - http://localhost:$HGPORT/?cmd=hello
- capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon
+ capabilities: * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (glob)
$ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities
- lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol)
+ * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol) (glob)
$ wget -q -O - "http://localhost:$HGPORT/?cmd=listkeys&namespace=namespaces" | sort
bookmarks
@@ -135,13 +137,13 @@
obsolete
phases
$ wget -q -O - http://localhost:$HGPORT/?cmd=hello
- capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon
+ capabilities: * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (glob)
$ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities
- lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol)
+ * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol) (glob)
$ echo '[__temporary__]' >> server/.hg/hgrc
$ echo 'advertiseobsolete=False' >> server/.hg/hgrc
- $ $TESTDIR/killdaemons.py
+ $ $TESTDIR/killdaemons.py $DAEMON_PIDS
$ hg serve -R server -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
@@ -149,13 +151,13 @@
bookmarks
namespaces
phases
- $ wget -q -O - http://localhost:$HGPORT/?cmd=hello
- capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
- $ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities
- lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 (no-eol)
+ $ wget -q -O - http://localhost:$HGPORT/?cmd=hello | grep _evoext_pushobsmarkers_0
+ [1]
+ $ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities | grep _evoext_pushobsmarkers_0
+ [1]
$ echo 'advertiseobsolete=True' >> server/.hg/hgrc
- $ $TESTDIR/killdaemons.py
+ $ $TESTDIR/killdaemons.py $DAEMON_PIDS
$ hg serve -R server -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
@@ -165,6 +167,6 @@
obsolete
phases
$ wget -q -O - http://localhost:$HGPORT/?cmd=hello
- capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon
+ capabilities: * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (glob)
$ wget -q -O - http://localhost:$HGPORT/?cmd=capabilities
- lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol)
+ * _evoext_pushobsmarkers_0 _evoext_pullobsmarkers_0 _evoext_obshash_0 _evoext_obshash_1 _evoext_getbundle_obscommon (no-eol) (glob)
--- a/tests/test-stabilize-order.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-stabilize-order.t Tue Jun 23 15:32:47 2015 -0700
@@ -153,8 +153,8 @@
$ hg up 9
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg evolve -v
- nothing to evolve here
- (1 troubled changesets, do you want --any ?)
+ nothing to evolve on current working copy parent
+ (1 other unstable in the repository, do you want --any or --rev)
[2]
$ hg evolve --any -v
move:[9] addc
@@ -180,5 +180,68 @@
o 0:c471ef929e6a@default(draft) addroot
$ hg evolve --any -v
- no troubled changesets
+ no unstable changesets to evolve
[1]
+
+Ambiguous evolution
+ $ echo a > k
+ $ hg add k
+ $ hg ci -m firstambiguous
+ $ hg up .^
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo a > l
+ $ hg add l
+ $ hg ci -m secondambiguous
+ created new head
+ $ hg up .^
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg commit --amend -m "newmessage"
+ 2 new unstable changesets
+ $ hg log -G
+ @ changeset: 15:49773ccde390
+ | tag: tip
+ | parent: 11:036cf654e942
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: newmessage
+ |
+ | o changeset: 14:a9892777b519
+ | | parent: 12:e99ecf51c867
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: secondambiguous
+ | |
+ | | o changeset: 13:0b6e26b2472d
+ | |/ user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: firstambiguous
+ | |
+ | x changeset: 12:e99ecf51c867
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: addc
+ |
+ o changeset: 11:036cf654e942
+ | parent: 7:005fe5914f78
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: addb
+ |
+ o changeset: 7:005fe5914f78
+ | parent: 0:c471ef929e6a
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: adda
+ |
+ o changeset: 0:c471ef929e6a
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: addroot
+
+ $ hg evolve
+ abort: multiple evolve candidates
+ (select one of *, * with --rev) (glob)
+ [255]
+
+
+
--- a/tests/test-stabilize-result.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-stabilize-result.t Tue Jun 23 15:32:47 2015 -0700
@@ -158,20 +158,20 @@
Stabilize!
- $ hg evolve --any --dry-run
+ $ hg evolve --any --dry-run --bumped
recreate:[12] newer a
atop:[8] newer a
hg rebase --rev (73b15c7566e9|d5c7ef82d003) --dest 66719795a494; (re)
hg update 1cf0aacfd363;
hg revert --all --rev (73b15c7566e9|d5c7ef82d003); (re)
hg commit --msg "bumped update to %s" (no-eol)
- $ hg evolve --any --confirm
+ $ hg evolve --any --confirm --bumped
recreate:[12] newer a
atop:[8] newer a
perform evolve? [Ny] n
abort: evolve aborted by user
[255]
- $ echo y | hg evolve --any --confirm --config ui.interactive=True
+ $ echo y | hg evolve --any --confirm --config ui.interactive=True --bumped
recreate:[12] newer a
atop:[8] newer a
perform evolve? [Ny] y
@@ -248,14 +248,14 @@
Stabilize it
- $ hg evolve -qn --confirm
+ $ hg evolve -qn --confirm --divergent
merge:[19] More addition
with: [17] More addition
base: [15] More addition
perform evolve? [Ny] n
abort: evolve aborted by user
[255]
- $ echo y | hg evolve -qn --confirm --config ui.interactive=True
+ $ echo y | hg evolve -qn --confirm --config ui.interactive=True --divergent
merge:[19] More addition
with: [17] More addition
base: [15] More addition
@@ -266,7 +266,7 @@
hg up -C 3932c176bbaa &&
hg revert --all --rev tip &&
hg commit -m "`hg log -r eacc9c8240fe --template={desc}`";
- $ hg evolve -v
+ $ hg evolve -v --divergent
merge:[19] More addition
with: [17] More addition
base: [15] More addition
@@ -306,6 +306,7 @@
branch: default
commit: (clean)
update: 2 new changesets, 2 branch heads (merge)
+ phases: 3 draft
$ hg export .
# HG changeset patch
# User test
@@ -343,14 +344,14 @@
$ hg phase 'divergent()'
21: draft
24: draft
- $ hg evolve -qn
+ $ hg evolve -qn --divergent
hg update -c 0b336205a5d0 &&
hg merge f344982e63c4 &&
hg commit -m "auto merge resolving conflict between 0b336205a5d0 and f344982e63c4"&&
hg up -C 3932c176bbaa &&
hg revert --all --rev tip &&
hg commit -m "`hg log -r 0b336205a5d0 --template={desc}`";
- $ hg evolve
+ $ hg evolve --divergent
merge:[24] More addition (2)
with: [21] More addition
base: [15] More addition
--- a/tests/test-tutorial.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-tutorial.t Tue Jun 23 15:32:47 2015 -0700
@@ -224,7 +224,6 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pull obsolescence markers
(run 'hg heads' to see heads, 'hg merge' to merge)
I now have a new heads. Note that this remote head is immutable
@@ -289,9 +288,9 @@
not fit well in my standard shopping list)
$ hg prune . # "." is for working directory parent
- 1 changesets pruned
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
working directory now at 41aff6a42b75
+ 1 changesets pruned
The silly changeset is gone.
@@ -406,8 +405,7 @@
adding manifests
adding file changes
added 3 changesets with 3 changes to 1 files
- pushing 6 obsolescence markers (* bytes) (glob)
- 6 obsolescence markers added
+ 6 new obsolescence markers
for simplicity sake we get the bathroom change in line again
@@ -528,8 +526,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pull obsolescence markers
- 1 obsolescence markers added
+ 1 new obsolescence markers
(run 'hg update' to get a working copy)
$ hg log -G
o 75954b8cd933 (public): bathroom stuff
@@ -586,8 +583,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pull obsolescence markers
- 1 obsolescence markers added
+ 1 new obsolescence markers
(run 'hg update' to get a working copy)
$ hg log -G
o 75954b8cd933 (draft): bathroom stuff
@@ -647,8 +643,6 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
- pull obsolescence markers
- 0 obsolescence markers added
(run 'hg heads' to see heads, 'hg merge' to merge)
1 new unstable changesets
@@ -738,8 +732,7 @@
adding manifests
adding file changes
added 2 changesets with 2 changes to 1 files (+1 heads)
- pushing 10 obsolescence markers (* bytes) (glob)
- 3 obsolescence markers added
+ 3 new obsolescence markers
remote get a warning that current working directory is based on an obsolete changeset
@@ -748,8 +741,6 @@
pulling from $TESTTMP/local (glob)
searching for changes
no changes found
- pull obsolescence markers
- 0 obsolescence markers added
working directory parent is obsolete!
now let's see where we are, and update to the successor
@@ -780,8 +771,6 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
- pull obsolescence markers
- 0 obsolescence markers added
(run 'hg update' to get a working copy)
$ hg log -G
o 99f039c5ec9e (draft): SPAM SPAM SPAM
@@ -804,9 +793,9 @@
In the mean time I noticed you can't buy animals in a super market and I prune the animal changeset:
$ hg prune ee942144f952
- 1 changesets pruned
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
working directory now at a44c85f957d3
+ 1 changesets pruned
1 new unstable changesets
--- a/tests/test-uncommit.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-uncommit.t Tue Jun 23 15:32:47 2015 -0700
@@ -138,7 +138,6 @@
$ hg branch foo
marked working directory as branch foo
- (branches are permanent and global, did you want a bookmark?)
$ hg mv ff f
$ hg mv h i
$ hg rm j
--- a/tests/test-userguide.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-userguide.t Tue Jun 23 15:32:47 2015 -0700
@@ -66,9 +66,9 @@
$ echo 'debug hack' >> file1.c
$ hg commit -m 'debug hack'
$ hg prune .
- 1 changesets pruned
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
working directory now at 934359450037
+ 1 changesets pruned
$ hg parents --template '{rev}:{node|short} {desc|firstline}\n'
3:934359450037 implement feature Y
$ hg --hidden shortlog -G -r 3:
@@ -219,7 +219,7 @@
|
o 18:1f33e68b18b9 draft useful work
|
- $ hg evolve -q --all
+ $ hg evolve -q --all --any
$ hg --hidden shortlog -G -r 18::
@ 21:4393e5877437 draft more work
|
@@ -251,7 +251,7 @@
$ hg status
M file2.c
$ hg revert file2.c
- $ hg evolve --all
+ $ hg evolve --all --any
move:[23] fix bug 67
atop:[24] fix bug 53
working directory is now at 0d972d6888e6
@@ -300,7 +300,7 @@
|/
o 25:0d972d6888e6 draft fix bug 67
|
- $ hg evolve --all
+ $ hg evolve --all --any
move:[27] new feature
atop:[28] fix a bug
working directory is now at 166c1c368ab6
--- a/tests/test-wireproto-bundle1.t Tue Jun 23 15:32:15 2015 -0700
+++ b/tests/test-wireproto-bundle1.t Tue Jun 23 15:32:47 2015 -0700
@@ -50,7 +50,6 @@
adding manifests
adding file changes
added 2 changesets with 2 changes to 2 files
- pull obsolescence markers
(run 'hg update' to get a working copy)
$ hg push -R ../other
pushing to ssh://user@dummy/server
@@ -70,8 +69,7 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files (+1 heads)
- pushing 2 obsolescence markers (* bytes) (glob)
- remote: 2 obsolescence markers added
+ remote: 2 new obsolescence markers
$ hg push
pushing to ssh://user@dummy/server
searching for changes
@@ -88,9 +86,8 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
- pull obsolescence markers
- 2 obsolescence markers added
- (run 'hg heads' to see heads)
+ 2 new obsolescence markers
+ (run 'hg heads' to see heads, 'hg merge' to merge)
$ hg -R ../other pull
pulling from ssh://user@dummy/server
searching for changes