--- a/CHANGELOG Tue Jan 22 10:43:44 2019 -0500
+++ b/CHANGELOG Tue Jan 22 10:46:02 2019 -0500
@@ -1,6 +1,29 @@
Changelog
=========
+8.4.0 - in progress
+-------------------
+
+ * split: improve and update the user prompt (BC)
+ * split: make it possible to drop change during a split
+ * split: no longer accept revision with --rev (BC)
+ * split: accept file patterns
+ * split: support for non interactive splits
+ * evolve: avoid potential crash when stabilizing orphan merges
+ * evolve: pick right destination in split+prune cases issue5686 (4.9 only)
+ * evolve: prioritize --rev/--any/--all option over obsolete working directory
+ * fold: concatenate commit message in revision order
+ * push: have `--publish` overrule the `auto-publish` config
+ * next: evolve aspiring children by default (use --no-evolve to skip)
+ * next: pick lower part of a split as destination
+ * compat: drop compatibility with Mercurial 4.3
+ * compat: add compatibility with Mercurial 4.9
+ * topics: improve the message around topic changing
+ * stack: introduce a --children flag (see help for details)
+ * topic: make --age compatible with the usual other display for `hg topic`
+ * stack: support for '#stack[idx]' absolute indexing in revset (4.9+ only)
+ * topic: support for '#topic[idx]' relative indexing in revset (4.9+ only)
+
8.3.3 -- 2017-12-24
-------------------
--- a/hgext3rd/evolve/__init__.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/__init__.py Tue Jan 22 10:46:02 2019 -0500
@@ -2,6 +2,7 @@
# Logilab SA <contact@logilab.fr>
# Pierre-Yves David <pierre-yves.david@ens-lyon.org>
# Patrick Mezard <patrick@mezard.eu>
+# Octobus <contact@octobus.net>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
@@ -32,7 +33,7 @@
backported to older version of Mercurial by this extension. Some older
experimental protocol are also supported for a longer time in the extensions to
help people transitioning. (The extensions is currently compatible down to
-Mercurial version 4.3).
+Mercurial version 4.4).
New Config::
@@ -285,7 +286,6 @@
context,
dirstate,
error,
- extensions,
help,
hg,
lock as lockmod,
@@ -364,20 +364,18 @@
eh.merge(compat.eh)
eh.merge(cmdrewrite.eh)
eh.merge(rewind.eh)
-uisetup = eh.final_uisetup
-extsetup = eh.final_extsetup
-reposetup = eh.final_reposetup
+uisetup = eh.finaluisetup
+extsetup = eh.finalextsetup
+reposetup = eh.finalreposetup
cmdtable = eh.cmdtable
configtable = eh.configtable
+revsetpredicate = eh.revsetpredicate
+templatekeyword = eh.templatekeyword
# Configuration
-eh.configitem('experimental', 'evolutioncommands')
-eh.configitem('experimental', 'evolution.allnewcommands')
-eh.configitem('experimental', 'prunestrip')
-
-# hack around because we need an actual default there
-if configtable:
- configtable['experimental']['evolution.allnewcommands'].default = None
+eh.configitem('experimental', 'evolutioncommands', [])
+eh.configitem('experimental', 'evolution.allnewcommands', None)
+eh.configitem('experimental', 'prunestrip', False)
# pre hg 4.0 compat
@@ -435,7 +433,7 @@
# 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.
- evolvecommands = ui.configlist('experimental', 'evolutioncommands', [])
+ evolvecommands = ui.configlist('experimental', 'evolutioncommands')
evolveopts = ui.configlist('experimental', 'evolution')
if evolveopts and (commandopt not in evolveopts
and 'all' not in evolveopts):
@@ -516,7 +514,7 @@
### Troubled revset symbol
-@eh.revset('troubled()')
+@eh.revsetpredicate('troubled()')
def revsettroubled(repo, subset, x):
"""Changesets with troubles.
"""
@@ -624,7 +622,7 @@
### XXX I'm not sure this revset is useful
-@eh.revset('suspended()')
+@eh.revsetpredicate('suspended()')
def revsetsuspended(repo, subset, x):
"""Obsolete changesets with non-obsolete descendants.
"""
@@ -634,7 +632,7 @@
return subset & suspended
-@eh.revset('precursors(set)')
+@eh.revsetpredicate('precursors(set)')
def revsetprecursors(repo, subset, x):
"""Immediate precursors of changesets in set.
"""
@@ -644,7 +642,7 @@
return subset & s
-@eh.revset('allprecursors(set)')
+@eh.revsetpredicate('allprecursors(set)')
def revsetallprecursors(repo, subset, x):
"""Transitive precursors of changesets in set.
"""
@@ -654,7 +652,7 @@
return subset & s
-@eh.revset('successors(set)')
+@eh.revsetpredicate('successors(set)')
def revsetsuccessors(repo, subset, x):
"""Immediate successors of changesets in set.
"""
@@ -663,7 +661,7 @@
s.sort()
return subset & s
-@eh.revset('allsuccessors(set)')
+@eh.revsetpredicate('allsuccessors(set)')
def revsetallsuccessors(repo, subset, x):
"""Transitive successors of changesets in set.
"""
@@ -781,45 +779,6 @@
_warnobsoletewc(ui, repo)
return res
-# XXX this could wrap transaction code
-# XXX (but this is a bit a layer violation)
-@eh.wrapcommand("commit")
-@eh.wrapcommand("import")
-@eh.wrapcommand("push")
-@eh.wrapcommand("pull")
-@eh.wrapcommand("graft")
-@eh.wrapcommand("phase")
-@eh.wrapcommand("unbundle")
-def warnobserrors(orig, ui, repo, *args, **kwargs):
- """display warning is the command resulted in more instable changeset"""
- # hg < 4.4 does not have the feature built in. bail out otherwise.
- if util.safehasattr(scmutil, '_reportstroubledchangesets'):
- return orig(ui, repo, *args, **kwargs)
-
- # part of the troubled stuff may be filtered (stash ?)
- # This needs a better implementation but will probably wait for core.
- filtered = repo.changelog.filteredrevs
- priorunstables = len(set(getrevs(repo, 'orphan')) - filtered)
- priorbumpeds = len(set(getrevs(repo, 'phasedivergent')) - filtered)
- priordivergents = len(set(getrevs(repo, 'contentdivergent')) - filtered)
- ret = orig(ui, repo, *args, **kwargs)
- filtered = repo.changelog.filteredrevs
- newunstables = \
- len(set(getrevs(repo, 'orphan')) - filtered) - priorunstables
- newbumpeds = \
- len(set(getrevs(repo, 'phasedivergent')) - filtered) - priorbumpeds
- newdivergents = \
- len(set(getrevs(repo, 'contentdivergent')) - filtered) - priordivergents
-
- base_msg = _('%i new %s changesets\n')
- if newunstables > 0:
- ui.warn(base_msg % (newunstables, compat.TROUBLES['ORPHAN']))
- if newbumpeds > 0:
- ui.warn(base_msg % (newbumpeds, compat.TROUBLES['PHASEDIVERGENT']))
- if newdivergents > 0:
- ui.warn(base_msg % (newdivergents, compat.TROUBLES['CONTENTDIVERGENT']))
- return ret
-
@eh.wrapfunction(mercurial.exchange, 'push')
def push(orig, repo, *args, **opts):
"""Add a hint for "hg evolve" when troubles make push fails
@@ -845,28 +804,6 @@
def obssummarysetup(ui):
cmdutil.summaryhooks.add('evolve', summaryhook)
-
-#####################################################################
-### Core Other extension compat ###
-#####################################################################
-
-
-@eh.extsetup
-def _rebasewrapping(ui):
- # warning about more obsolete
- try:
- rebase = extensions.find('rebase')
- if rebase:
- extensions.wrapcommand(rebase.cmdtable, 'rebase', warnobserrors)
- except KeyError:
- pass # rebase not found
- try:
- histedit = extensions.find('histedit')
- if histedit:
- extensions.wrapcommand(histedit.cmdtable, 'histedit', warnobserrors)
- except KeyError:
- pass # histedit not found
-
#####################################################################
### Old Evolve extension content ###
#####################################################################
@@ -1071,11 +1008,7 @@
if ui.config('commands', 'update.check') == 'noconflict':
pass
else:
- try:
- cmdutil.bailifchanged(repo)
- except error.Abort as exc:
- exc.hint = _('do you want --merge?')
- raise
+ cmdutil.bailifchanged(repo, hint=_('do you want --merge?'))
topic = not opts.get("no_topic", False)
hastopic = bool(_getcurrenttopic(repo))
@@ -1109,7 +1042,7 @@
[('B', 'move-bookmark', False,
_('move active bookmark after update')),
('m', 'merge', False, _('bring uncommitted change along')),
- ('', 'evolve', False, _('evolve the next changeset if necessary')),
+ ('', 'evolve', True, _('evolve the next changeset if necessary')),
('', 'no-topic', False, _('ignore topic and move topologically')),
('n', 'dry-run', False,
_('do not perform actions, just print what would be done'))],
@@ -1118,7 +1051,8 @@
def cmdnext(ui, repo, **opts):
"""update to next child revision
- Use the ``--evolve`` flag to evolve unstable children on demand.
+ If necessary, evolve the next changeset. Use --no-evolve to disable this
+ behavior.
Displays the summary line of the destination for clarity.
"""
@@ -1132,21 +1066,6 @@
if len(wparents) != 1:
raise error.Abort(_('merge in progress'))
- # check for dirty wdir if --evolve is passed
- if opts['evolve']:
- cmdutil.bailifchanged(repo)
-
- if not opts['merge']:
- # we only skip the check if noconflict is set
- if ui.config('commands', 'update.check') == 'noconflict':
- pass
- else:
- try:
- cmdutil.bailifchanged(repo)
- except error.Abort as exc:
- exc.hint = _('do you want --merge?')
- raise
-
children = [ctx for ctx in wparents[0].children() if not ctx.obsolete()]
topic = _getcurrenttopic(repo)
filtered = set()
@@ -1155,7 +1074,41 @@
filtered = set(ctx for ctx in children if ctx.topic() != topic)
children = [ctx for ctx in children if ctx not in filtered]
template = utility.stacktemplate
+ opts['stacktemplate'] = True
displayer = compat.changesetdisplayer(ui, repo, {'template': template})
+
+ # check if we need to evolve while updating to the next child revision
+ needevolve = False
+ aspchildren = evolvecmd._aspiringchildren(repo, [repo['.'].rev()])
+ if topic:
+ filtered.update(repo[c] for c in aspchildren
+ if repo[c].topic() != topic)
+ aspchildren = [ctx for ctx in aspchildren if ctx not in filtered]
+
+ # To catch and prevent the case when `next` would get confused by split,
+ # lets filter those aspiring children which can be stablized on one of
+ # the aspiring children itself.
+ aspirants = set(aspchildren)
+ for aspchild in aspchildren:
+ possdests = evolvecmd._possibledestination(repo, aspchild)
+ if possdests & aspirants:
+ filtered.add(aspchild)
+ aspchildren = [ctx for ctx in aspchildren if ctx not in filtered]
+ if aspchildren:
+ needevolve = True
+
+ # check if working directory is clean before we evolve the next cset
+ if needevolve and opts['evolve']:
+ hint = _('use `hg amend`, `hg revert` or `hg shelve`')
+ cmdutil.bailifchanged(repo, hint=hint)
+
+ if not (opts['merge'] or (needevolve and opts['evolve'])):
+ # we only skip the check if noconflict is set
+ if ui.config('commands', 'update.check') == 'noconflict':
+ pass
+ else:
+ cmdutil.bailifchanged(repo, hint=_('do you want --merge?'))
+
if len(children) == 1:
c = children[0]
return _updatetonext(ui, repo, c, displayer, opts)
@@ -1172,11 +1125,6 @@
else:
return _updatetonext(ui, repo, repo[choosedrev], displayer, opts)
else:
- aspchildren = evolvecmd._aspiringchildren(repo, [repo['.'].rev()])
- if topic:
- filtered.update(repo[c] for c in aspchildren
- if repo[c].topic() != topic)
- aspchildren = [ctx for ctx in aspchildren if ctx not in filtered]
if not opts['evolve'] or not aspchildren:
if filtered:
ui.warn(_('no children on topic "%s"\n') % topic)
@@ -1188,7 +1136,7 @@
'do you want --evolve?)\n')
ui.warn(msg % len(aspchildren))
return 1
- elif 1 < len(aspchildren):
+ elif len(aspchildren) > 1:
cheader = _("ambiguous next (unstable) changeset, choose one to"
" evolve and update:")
choosedrev = utility.revselectionprompt(ui, repo,
@@ -1214,7 +1162,8 @@
'bookmarkchanges': []})
result = evolvecmd._solveone(ui, repo, repo[aspchildren],
evolvestate, opts.get('dry_run'), False,
- lambda: None, category='orphan')
+ lambda: None, category='orphan',
+ stacktmplt=opts.get('stacktemplate', False))
# making sure a next commit is formed
if result[0] and result[1]:
ui.status(_('working directory now at %s\n')
@@ -1303,7 +1252,7 @@
"backup bundle")),
])
def stripwrapper(orig, ui, repo, *revs, **kwargs):
- if (not ui.configbool('experimental', 'prunestrip', False)
+ if (not ui.configbool('experimental', 'prunestrip')
or kwargs.get('bundle', False)):
return orig(ui, repo, *revs, **kwargs)
@@ -1325,14 +1274,6 @@
@eh.extsetup
def oldevolveextsetup(ui):
- for cmd in ['prune', 'uncommit', 'touch', 'fold']:
- 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', [],
_("make commit obsolete this revision (DEPRECATED)")))
--- a/hgext3rd/evolve/cmdrewrite.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/cmdrewrite.py Tue Jan 22 10:46:02 2019 -0500
@@ -105,7 +105,7 @@
('', 'close-branch', None,
_('mark a branch as closed, hiding it from the branch list')),
('s', 'secret', None, _('use the secret phase for committing')),
- ('n', 'note', '', _('store a note on amend')),
+ ('n', 'note', '', _('store a note on amend'), _('TEXT')),
] + walkopts + commitopts + commitopts2 + commitopts3 + interactiveopt,
_('[OPTION]... [FILE]...'),
helpbasic=True)
@@ -462,9 +462,9 @@
'uncommit',
[('a', 'all', None, _('uncommit all changes when no arguments given')),
('i', 'interactive', False, _('interactive mode to uncommit (EXPERIMENTAL)')),
- ('r', 'rev', '', _('revert commit content to REV instead')),
+ ('r', 'rev', '', _('revert commit content to REV instead'), _('REV')),
('', 'revert', False, _('discard working directory changes after uncommit')),
- ('n', 'note', '', _('store a note on uncommit')),
+ ('n', 'note', '', _('store a note on uncommit'), _('TEXT')),
] + commands.walkopts + commitopts + commitopts2 + commitopts3,
_('[OPTION]... [NAME]'))
def uncommit(ui, repo, *pats, **opts):
@@ -662,10 +662,10 @@
@eh.command(
'fold|squash',
- [('r', 'rev', [], _("revision to fold")),
+ [('r', 'rev', [], _("revision to fold"), _('REV')),
('', 'exact', None, _("only fold specified revisions")),
('', 'from', None, _("fold revisions linearly to working copy parent")),
- ('n', 'note', '', _('store a note on fold')),
+ ('n', 'note', '', _('store a note on fold'), _('TEXT')),
] + commitopts + commitopts2 + commitopts3,
_('hg fold [OPTION]... [-r] REV'),
helpbasic=True)
@@ -740,6 +740,10 @@
ui.write_err(_('single revision specified, nothing to fold\n'))
return 1
+ # Sort so combined commit message of `hg fold --exact -r . -r .^` is
+ # in topological order.
+ revs.sort()
+
wlock = lock = None
try:
wlock = repo.wlock()
@@ -791,9 +795,9 @@
@eh.command(
'metaedit',
- [('r', 'rev', [], _("revision to edit")),
+ [('r', 'rev', [], _("revision to edit"), _('REV')),
('', 'fold', None, _("also fold specified revisions into one")),
- ('n', 'note', '', _('store a note on metaedit')),
+ ('n', 'note', '', _('store a note on metaedit'), _('TEXT')),
] + commitopts + commitopts2 + commitopts3,
_('hg metaedit [OPTION]... [-r] [REV]'))
def metaedit(ui, repo, *revs, **opts):
@@ -941,10 +945,10 @@
@eh.command(
'prune|obsolete',
[('n', 'new', [], _("successor changeset (DEPRECATED)")),
- ('s', 'succ', [], _("successor changeset")),
- ('r', 'rev', [], _("revisions to prune")),
+ ('s', 'succ', [], _("successor changeset"), _('REV')),
+ ('r', 'rev', [], _("revisions to prune"), _('REV')),
('k', 'keep', None, _("does not modify working copy during prune")),
- ('n', 'note', '', _('store a note on prune')),
+ ('n', 'note', '', _('store a note on prune'), _('TEXT')),
('', 'pair', False, _("record a pairing, such as a rebase or divergence resolution "
"(pairing multiple precursors to multiple successors)")),
('', 'biject', False, _("alias to --pair (DEPRECATED)")),
@@ -953,7 +957,7 @@
('', 'split', False,
_("record a split (on precursor, multiple successors)")),
('B', 'bookmark', [], _("remove revs only reachable from given"
- " bookmark"))] + metadataopts,
+ " bookmark"), _('BOOKMARK'))] + metadataopts,
_('[OPTION] [-r] REV...'),
helpbasic=True)
# XXX -U --noupdate option to prevent wc update and or bookmarks update ?
@@ -1132,29 +1136,39 @@
@eh.command(
'split',
- [('r', 'rev', [], _("revision to split")),
- ('n', 'note', '', _("store a note on split")),
+ [('i', 'interactive', True, _('use interactive mode')),
+ ('r', 'rev', [], _("revision to split"), _('REV')),
+ ('n', 'note', '', _("store a note on split"), _('TEXT')),
] + commitopts + commitopts2 + commitopts3,
- _('hg split [OPTION]... [-r] REV'),
+ _('hg split [OPTION] [-r REV] [FILES]'),
helpbasic=True)
-def cmdsplit(ui, repo, *revs, **opts):
+def cmdsplit(ui, repo, *pats, **opts):
"""split a changeset into smaller changesets
By default, split the current revision by prompting for all its hunks to be
redistributed into new changesets.
Use --rev to split a given changeset instead.
+
+ If file patterns are specified only files matching these patterns will be
+ considered to be split in earlier changesets. The files that doesn't match
+ will be gathered in the last changeset.
"""
_checknotesize(ui, opts)
_resolveoptions(ui, opts)
tr = wlock = lock = None
newcommits = []
+ iselect = opts.pop('interactive')
- revarg = (list(revs) + opts.get('rev')) or ['.']
- if len(revarg) != 1:
- msg = _("more than one revset is given")
- hnt = _("use either `hg split <rs>` or `hg split --rev <rs>`, not both")
- raise error.Abort(msg, hint=hnt)
+ revs = opts.get('rev') or '.'
+ if not revs:
+ revarg = '.'
+ elif len(revs) == 1:
+ revarg = revs[0]
+ else:
+ # XXX --rev often accept multiple value, it seems safer to explicitly
+ # complains here instead of just taking the last value.
+ raise error.Abort(_('more than one revset is given'))
# Save the current branch to restore it in the end
savedbranch = repo.dirstate.branch()
@@ -1162,7 +1176,7 @@
try:
wlock = repo.wlock()
lock = repo.lock()
- ctx = scmutil.revsingle(repo, revarg[0])
+ ctx = scmutil.revsingle(repo, revarg)
rev = ctx.rev()
cmdutil.bailifchanged(repo)
rewriteutil.precheck(repo, [rev], action='split')
@@ -1180,8 +1194,8 @@
# Prepare the working directory
rewriteutil.presplitupdate(repo, ui, prev, ctx)
- def haschanges():
- modified, added, removed, deleted = repo.status()[:4]
+ def haschanges(matcher=None):
+ modified, added, removed, deleted = repo.status(match=matcher)[:4]
return modified or added or removed or deleted
msg = ("HG: This is the original pre-split commit message. "
"Edit it as appropriate.\n\n")
@@ -1195,21 +1209,79 @@
# XXX-TODO: Find a way to set the branch without altering the dirstate
repo.dirstate.setbranch(ctx.branch())
+ if pats:
+ # refresh the wctx used for the matcher
+ matcher = scmutil.match(repo[None], pats)
+ else:
+ matcher = scmutil.matchall(repo)
+
while haschanges():
- pats = ()
- cmdutil.dorecord(ui, repo, commands.commit, 'commit', False,
- cmdutil.recordfilter, *pats, **opts)
- # TODO: Does no seem like the best way to do this
- # We should make dorecord return the newly created commit
- newcommits.append(repo['.'])
- if haschanges():
- if ui.prompt('Done splitting? [yN]', default='n') == 'y':
+
+ if haschanges(matcher):
+ if iselect:
+ cmdutil.dorecord(ui, repo, commands.commit, 'commit', False,
+ cmdutil.recordfilter, *pats, **opts)
+ # TODO: Does no seem like the best way to do this
+ # We should make dorecord return the newly created commit
+ newcommits.append(repo['.'])
+ elif not pats:
+ msg = _("no files of directories specified")
+ hint = _("do you want --interactive")
+ raise error.Abort(msg, hint=hint)
+ else:
+ commands.commit(ui, repo, *pats, **opts)
+ newcommits.append(repo['.'])
+ if pats:
+ # refresh the wctx used for the matcher
+ matcher = scmutil.match(repo[None], pats)
+ else:
+ matcher = scmutil.matchall(repo)
+
+ if haschanges(matcher):
+ nextaction = None
+ while nextaction is None:
+ nextaction = ui.prompt('continue splitting? [Ycdq?]', default='y')
+ if nextaction == 'c':
+ commands.commit(ui, repo, **opts)
+ newcommits.append(repo['.'])
+ break
+ elif nextaction == 'q':
+ raise error.Abort(_('user quit'))
+ elif nextaction == 'd':
+ # TODO: We should offer a way for the user to confirm
+ # what is the remaining changes, either via a separate
+ # diff action or by showing the remaining and
+ # prompting for confirmation
+ ui.status(_('discarding remaining changes\n'))
+ target = newcommits[0]
+ if pats:
+ status = repo.status(match=matcher)[:4]
+ dirty = set()
+ for i in status:
+ dirty.update(i)
+ dirty = sorted(dirty)
+ cmdutil.revert(ui, repo, repo[target],
+ (target, node.nullid), *dirty)
+ else:
+ cmdutil.revert(ui, repo, repo[target],
+ (target, node.nullid), all=True)
+ elif nextaction == '?':
+ nextaction = None
+ ui.write(_("y - yes, continue selection\n"))
+ ui.write(_("c - commit, select all remaining changes\n"))
+ ui.write(_("d - discard, discard remaining changes\n"))
+ ui.write(_("q - quit, abort the split\n"))
+ ui.write(_("? - ?, display help\n"))
+ else:
+ continue
+ break # propagate the previous break
+ else:
+ ui.status(_("no more change to split\n"))
+ if haschanges():
+ # XXX: Should we show a message for informing the user
+ # that we create another commit with remaining changes?
commands.commit(ui, repo, **opts)
newcommits.append(repo['.'])
- break
- else:
- ui.status(_("no more change to split\n"))
-
if newcommits:
tip = repo[newcommits[-1]]
bmupdate(tip.node())
@@ -1229,8 +1301,8 @@
@eh.command(
'touch',
- [('r', 'rev', [], 'revision to update'),
- ('n', 'note', '', _('store a note on touch')),
+ [('r', 'rev', [], _('revision to update'), _('REV')),
+ ('n', 'note', '', _('store a note on touch'), _('TEXT')),
('D', 'duplicate', False,
'do not mark the new revision as successor of the old one'),
('A', 'allowdivergence', False,
@@ -1322,7 +1394,7 @@
@eh.command(
'pick|grab',
- [('r', 'rev', '', 'revision to pick'),
+ [('r', 'rev', '', _('revision to pick'), _('REV')),
('c', 'continue', False, 'continue interrupted pick'),
('a', 'abort', False, 'abort interrupted pick'),
],
--- a/hgext3rd/evolve/compat.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/compat.py Tue Jan 22 10:46:02 2019 -0500
@@ -19,6 +19,7 @@
revset,
scmutil,
util,
+ ui as uimod,
vfs as vfsmod,
)
from mercurial.hgweb import hgweb_mod
@@ -77,20 +78,31 @@
context.basectx.isunstable = context.basectx.troubled
if not util.safehasattr(revset, 'orphan'):
- @eh.revset('orphan')
+ @eh.revsetpredicate('orphan')
def oprhanrevset(*args, **kwargs):
return revset.unstable(*args, **kwargs)
if not util.safehasattr(revset, 'contentdivergent'):
- @eh.revset('contentdivergent')
+ @eh.revsetpredicate('contentdivergent')
def contentdivergentrevset(*args, **kwargs):
return revset.divergent(*args, **kwargs)
if not util.safehasattr(revset, 'phasedivergent'):
- @eh.revset('phasedivergent')
+ @eh.revsetpredicate('phasedivergent')
def phasedivergentrevset(*args, **kwargs):
return revset.bumped(*args, **kwargs)
+if util.safehasattr(uimod.ui, 'makeprogress'):
+ def progress(ui, topic, pos, item="", unit="", total=None):
+ progress = ui.makeprogress(topic, unit, total)
+ if pos is not None:
+ progress.update(pos, item=item)
+ else:
+ progress.complete()
+else:
+ def progress(ui, topic, pos, item="", unit="", total=None):
+ ui.progress(topic, pos, item="", unit="", total=None)
+
if not util.safehasattr(context.basectx, 'instabilities'):
def instabilities(self):
"""return the list of instabilities affecting this changeset.
@@ -466,256 +478,8 @@
return copy, movewithdir, diverge, renamedelete, dirmove
-# code imported from Mercurial core at 4.3 + patch
-def fixoldmergecopies(repo, c1, c2, base):
-
- from mercurial import pathutil
-
- # avoid silly behavior for update from empty dir
- if not c1 or not c2 or c1 == c2:
- return {}, {}, {}, {}, {}
-
- # avoid silly behavior for parent -> working dir
- if c2.node() is None and c1.node() == repo.dirstate.p1():
- return repo.dirstate.copies(), {}, {}, {}, {}
-
- # Copy trace disabling is explicitly below the node == p1 logic above
- # because the logic above is required for a simple copy to be kept across a
- # rebase.
- if repo.ui.configbool('experimental', 'disablecopytrace'):
- return {}, {}, {}, {}, {}
-
- # In certain scenarios (e.g. graft, update or rebase), base can be
- # overridden We still need to know a real common ancestor in this case We
- # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
- # can be multiple common ancestors, e.g. in case of bidmerge. Because our
- # caller may not know if the revision passed in lieu of the CA is a genuine
- # common ancestor or not without explicitly checking it, it's better to
- # determine that here.
- #
- # base.descendant(wc) and base.descendant(base) are False, work around that
- _c1 = c1.p1() if c1.rev() is None else c1
- _c2 = c2.p1() if c2.rev() is None else c2
- # an endpoint is "dirty" if it isn't a descendant of the merge base
- # if we have a dirty endpoint, we need to trigger graft logic, and also
- # keep track of which endpoint is dirty
- dirtyc1 = not (base == _c1 or base.descendant(_c1))
- dirtyc2 = not (base == _c2 or base.descendant(_c2))
- graft = dirtyc1 or dirtyc2
- tca = base
- if graft:
- tca = _c1.ancestor(_c2)
-
- limit = copies._findlimit(repo, c1.rev(), c2.rev())
- if limit is None:
- # no common ancestor, no copies
- return {}, {}, {}, {}, {}
- repo.ui.debug(" searching for copies back to rev %d\n" % limit)
-
- m1 = c1.manifest()
- m2 = c2.manifest()
- mb = base.manifest()
-
- # gather data from _checkcopies:
- # - diverge = record all diverges in this dict
- # - copy = record all non-divergent copies in this dict
- # - fullcopy = record all copies in this dict
- # - incomplete = record non-divergent partial copies here
- # - incompletediverge = record divergent partial copies here
- diverge = {} # divergence data is shared
- incompletediverge = {}
- data1 = {'copy': {},
- 'fullcopy': {},
- 'incomplete': {},
- 'diverge': diverge,
- 'incompletediverge': incompletediverge,
- }
- data2 = {'copy': {},
- 'fullcopy': {},
- 'incomplete': {},
- 'diverge': diverge,
- 'incompletediverge': incompletediverge,
- }
-
- # find interesting file sets from manifests
- addedinm1 = m1.filesnotin(mb)
- addedinm2 = m2.filesnotin(mb)
- bothnew = sorted(addedinm1 & addedinm2)
- if tca == base:
- # unmatched file from base
- u1r, u2r = copies._computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
- u1u, u2u = u1r, u2r
- else:
- # unmatched file from base (DAG rotation in the graft case)
- u1r, u2r = copies._computenonoverlap(repo, c1, c2, addedinm1, addedinm2,
- baselabel='base')
- # unmatched file from topological common ancestors (no DAG rotation)
- # need to recompute this for directory move handling when grafting
- mta = tca.manifest()
- u1u, u2u = copies._computenonoverlap(repo, c1, c2, m1.filesnotin(mta),
- m2.filesnotin(mta),
- baselabel='topological common ancestor')
-
- for f in u1u:
- copies._checkcopies(c1, c2, f, base, tca, dirtyc1, limit, data1)
-
- for f in u2u:
- copies._checkcopies(c2, c1, f, base, tca, dirtyc2, limit, data2)
-
- copy = dict(data1['copy'])
- copy.update(data2['copy'])
- fullcopy = dict(data1['fullcopy'])
- fullcopy.update(data2['fullcopy'])
-
- if dirtyc1:
- copies._combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
- incompletediverge)
- else:
- copies._combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
- incompletediverge)
-
- renamedelete = {}
- renamedeleteset = set()
- divergeset = set()
- for of, fl in diverge.items():
- if len(fl) == 1 or of in c1 or of in c2:
- del diverge[of] # not actually divergent, or not a rename
- if of not in c1 and of not in c2:
- # renamed on one side, deleted on the other side, but filter
- # out files that have been renamed and then deleted
- renamedelete[of] = [f for f in fl if f in c1 or f in c2]
- renamedeleteset.update(fl) # reverse map for below
- else:
- divergeset.update(fl) # reverse map for below
-
- if bothnew:
- repo.ui.debug(" unmatched files new in both:\n %s\n"
- % "\n ".join(bothnew))
- bothdiverge = {}
- bothincompletediverge = {}
- remainder = {}
- both1 = {'copy': {},
- 'fullcopy': {},
- 'incomplete': {},
- 'diverge': bothdiverge,
- 'incompletediverge': bothincompletediverge
- }
- both2 = {'copy': {},
- 'fullcopy': {},
- 'incomplete': {},
- 'diverge': bothdiverge,
- 'incompletediverge': bothincompletediverge
- }
- for f in bothnew:
- copies._checkcopies(c1, c2, f, base, tca, dirtyc1, limit, both1)
- copies._checkcopies(c2, c1, f, base, tca, dirtyc2, limit, both2)
- if dirtyc1 and dirtyc2:
- pass
- elif dirtyc1:
- # incomplete copies may only be found on the "dirty" side for bothnew
- assert not both2['incomplete']
- remainder = copies._combinecopies({}, both1['incomplete'], copy, bothdiverge,
- bothincompletediverge)
- elif dirtyc2:
- assert not both1['incomplete']
- remainder = copies._combinecopies({}, both2['incomplete'], copy, bothdiverge,
- bothincompletediverge)
- else:
- # incomplete copies and divergences can't happen outside grafts
- assert not both1['incomplete']
- assert not both2['incomplete']
- assert not bothincompletediverge
- for f in remainder:
- assert f not in bothdiverge
- ic = remainder[f]
- if ic[0] in (m1 if dirtyc1 else m2):
- # backed-out rename on one side, but watch out for deleted files
- bothdiverge[f] = ic
- for of, fl in bothdiverge.items():
- if len(fl) == 2 and fl[0] == fl[1]:
- copy[fl[0]] = of # not actually divergent, just matching renames
-
- if fullcopy and repo.ui.debugflag:
- repo.ui.debug(" all copies found (* = to merge, ! = divergent, "
- "% = renamed and deleted):\n")
- for f in sorted(fullcopy):
- note = ""
- if f in copy:
- note += "*"
- if f in divergeset:
- note += "!"
- if f in renamedeleteset:
- note += "%"
- repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
- note))
- del divergeset
-
- if not fullcopy:
- return copy, {}, diverge, renamedelete, {}
-
- repo.ui.debug(" checking for directory renames\n")
-
- # generate a directory move map
- d1, d2 = c1.dirs(), c2.dirs()
- # Hack for adding '', which is not otherwise added, to d1 and d2
- d1.addpath('/')
- d2.addpath('/')
- invalid = set()
- dirmove = {}
-
- # examine each file copy for a potential directory move, which is
- # when all the files in a directory are moved to a new directory
- for dst, src in fullcopy.iteritems():
- dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
- if dsrc in invalid:
- # already seen to be uninteresting
- continue
- elif dsrc in d1 and ddst in d1:
- # directory wasn't entirely moved locally
- invalid.add(dsrc + "/")
- elif dsrc in d2 and ddst in d2:
- # directory wasn't entirely moved remotely
- invalid.add(dsrc + "/")
- elif dsrc + "/" in dirmove and dirmove[dsrc + "/"] != ddst + "/":
- # files from the same directory moved to two different places
- invalid.add(dsrc + "/")
- else:
- # looks good so far
- dirmove[dsrc + "/"] = ddst + "/"
-
- for i in invalid:
- if i in dirmove:
- del dirmove[i]
- del d1, d2, invalid
-
- if not dirmove:
- return copy, {}, diverge, renamedelete, {}
-
- for d in dirmove:
- repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
- (d, dirmove[d]))
-
- movewithdir = {}
- # check unaccounted nonoverlapping files against directory moves
- for f in u1r + u2r:
- if f not in fullcopy:
- for d in dirmove:
- if f.startswith(d):
- # new file added in a directory that was moved, move it
- df = dirmove[d] + f[len(d):]
- if df not in copy:
- movewithdir[f] = df
- repo.ui.debug((" pending file src: '%s' -> "
- "dst: '%s'\n") % (f, df))
- break
-
- return copy, movewithdir, diverge, renamedelete, dirmove
-
if util.safehasattr(copies, '_fullcopytracing'):
copies._fullcopytracing = fixedcopytracing
-elif util.safehasattr(copies, 'mergecopies'):
- # compat fix for hg <= 4.3
- copies.mergecopies = fixoldmergecopies
if not util.safehasattr(obsutil, "_succs"):
class _succs(list):
--- a/hgext3rd/evolve/depthcache.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/depthcache.py Tue Jan 22 10:46:02 2019 -0500
@@ -113,8 +113,8 @@
total = len(data)
def progress(pos, rev):
- repo.ui.progress('updating depth cache',
- pos, 'rev %s' % rev, unit='revision', total=total)
+ compat.progress(repo.ui, 'updating depth cache',
+ pos, 'rev %s' % rev, unit='revision', total=total)
progress(0, '')
for idx, rev in enumerate(data, 1):
assert rev == len(self._data), (rev, len(self._data))
--- a/hgext3rd/evolve/evolvecmd.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/evolvecmd.py Tue Jan 22 10:46:02 2019 -0500
@@ -716,10 +716,7 @@
" content-divergent changesets.\nHG: Resolve conflicts"
" in commit messages to continue.\n\n")
- if 5 <= len(ui.edit.im_func.func_defaults): # <= hg-4.3
- resolveddesc = ui.edit(prefixes + desc, ui.username(), action='desc')
- else:
- resolveddesc = ui.edit(prefixes + desc, ui.username())
+ resolveddesc = ui.edit(prefixes + desc, ui.username(), action='desc')
# make sure we remove the prefixes part from final commit message
if prefixes in resolveddesc:
# hack, we should find something better
@@ -1297,7 +1294,7 @@
def _cleanup(ui, repo, startnode, showprogress, shouldupdate):
if showprogress:
- ui.progress(_('evolve'), None)
+ compat.progress(ui, _('evolve'), None)
if not shouldupdate:
unfi = repo.unfiltered()
@@ -1310,10 +1307,7 @@
"""Compute sets of commits divergent with a given one"""
cache = {}
base = {}
- allpredecessors = getattr(obsutil, 'allpredecessors', None)
- if allpredecessors is None: # <= Mercurial 4.3
- allpredecessors = obsutil.allprecursors
- for n in allpredecessors(repo.obsstore, [ctx.node()]):
+ for n in obsutil.allpredecessors(repo.obsstore, [ctx.node()]):
if n == ctx.node():
# a node can't be a base for divergence with itself
continue
@@ -1344,7 +1338,7 @@
('A', 'any', False,
_('also consider troubled changesets unrelated to current working '
'directory')),
- ('r', 'rev', [], _('solves troubles of these revisions')),
+ ('r', 'rev', [], _('solves troubles of these revisions'), _('REV')),
('', 'bumped', False, _('solves only bumped changesets (DEPRECATED)')),
('', 'phase-divergent', False, _('solves only phase-divergent changesets')),
('', 'divergent', False, _('solves only divergent changesets (DEPRECATED)')),
@@ -1484,36 +1478,9 @@
raise error.Abort(msg)
elif len(specifiedcategories) == 1:
targetcat = specifiedcategories[0]
- elif repo['.'].obsolete():
- oldid = repo['.'].node()
- displayer = compat.changesetdisplayer(ui, repo,
- {'template': shorttemplate})
- # no args and parent is obsolete, update to successors
- try:
- ctx = repo[utility._singlesuccessor(repo, repo['.'])]
- except utility.MultipleSuccessorsError as 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())
- newid = ctx.node()
-
- if ctx != startnode:
- with repo.wlock(), repo.lock(), repo.transaction('evolve') as tr:
- bmupdater = rewriteutil.bookmarksupdater(repo, oldid, tr)
- bmupdater(newid)
- ui.status(_('working directory is now at %s\n') % ctx)
- return res
+ elif repo['.'].obsolete() and not(revopt or anyopt or allopt):
+ # if no args and parent is obsolete, update to successors
+ return solveobswdp(ui, repo, opts)
ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve')
troubled = set(repo.revs('troubled()'))
@@ -1525,7 +1492,7 @@
def progresscb():
if revopt or allopt:
- ui.progress(_('evolve'), seen, unit=_('changesets'), total=count)
+ compat.progress(ui, _('evolve'), seen, unit=_('changesets'), total=count)
evolvestate = state.cmdstate(repo)
# Continuation handling
@@ -1565,6 +1532,15 @@
revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat)
+ # Case: when wdir parent is obsolete and args passed.
+ # Handling it here otherwise `revs` set would change, after
+ # performing update to successor of obsolete wdir parent.
+ # (in case when user passes a revset related to wdir parent '.::')
+ if repo['.'].obsolete():
+ result = solveobswdp(ui, repo, opts)
+ if result != 0 or result is True:
+ return result
+
if not revs:
return _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat)
@@ -1584,14 +1560,14 @@
# to confirm that if atop msg should be suppressed to remove redundancy
lastsolved = None
- # check if revs to be evolved are in active topic to make sure that we
- # can use stack aliases s# in evolve msgs.
activetopic = getattr(repo, 'currenttopic', '')
for rev in revs:
curctx = repo[rev]
revtopic = getattr(curctx, 'topic', lambda: '')()
topicidx = getattr(curctx, 'topicidx', lambda: None)()
stacktmplt = False
+ # check if revision being evolved is in active topic to make sure
+ # that we can use stack aliases s# in evolve msgs.
if activetopic and (activetopic == revtopic) and topicidx is not None:
stacktmplt = True
progresscb()
@@ -1613,6 +1589,7 @@
stacktmplt=stacktmplt)
if ret[0]:
evolvestate['replacements'][curctx.node()] = ret[1]
+ lastsolved = ret[1]
else:
evolvestate['skippedrevs'].append(curctx.node())
@@ -1621,6 +1598,38 @@
progresscb()
_cleanup(ui, repo, startnode, showprogress, shouldupdate)
+def solveobswdp(ui, repo, opts):
+ oldid = repo['.'].node()
+ startnode = repo['.']
+ dryrunopt = opts.get('dry_run', False)
+ displayer = compat.changesetdisplayer(ui, repo,
+ {'template': shorttemplate})
+ try:
+ ctx = repo[utility._singlesuccessor(repo, repo['.'])]
+ except utility.MultipleSuccessorsError as 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())
+ newid = ctx.node()
+
+ if ctx != startnode:
+ with repo.wlock(), repo.lock(), repo.transaction('evolve') as tr:
+ bmupdater = rewriteutil.bookmarksupdater(repo, oldid, tr)
+ bmupdater(newid)
+ ui.status(_('working directory is now at %s\n') % ctx)
+ return res
+
def stopevolve(ui, repo, evolvestate):
"""logic for handling of `hg evolve --stop`"""
updated = False
@@ -1753,14 +1762,25 @@
# evolved to confirm that if atop msg should be suppressed to remove
# redundancy
lastsolved = None
+ activetopic = getattr(repo, 'currenttopic', '')
for rev in evolvestate['revs']:
# XXX: prevent this lookup by storing nodes instead of revnums
curctx = unfi[rev]
+
+ # check if we can use stack template
+ revtopic = getattr(curctx, 'topic', lambda: '')()
+ topicidx = getattr(curctx, 'topicidx', lambda: None)()
+ stacktmplt = False
+ if (activetopic and (activetopic == revtopic)
+ and topicidx is not None):
+ stacktmplt = True
+
if (curctx.node() not in evolvestate['replacements']
and curctx.node() not in evolvestate['skippedrevs']):
newnode = _solveone(ui, repo, curctx, evolvestate, False,
confirm, progresscb, category,
- lastsolved=lastsolved)
+ lastsolved=lastsolved,
+ stacktmplt=stacktmplt)
if newnode[0]:
evolvestate['replacements'][curctx.node()] = newnode[1]
lastsolved = newnode[1]
--- a/hgext3rd/evolve/exthelper.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/exthelper.py Tue Jan 22 10:46:02 2019 -0500
@@ -1,38 +1,82 @@
+# Copyright 2012 Logilab SA <contact@logilab.fr>
+# Pierre-Yves David <pierre-yves.david@ens-lyon.org>
+# Octobus <contact@octobus.net>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
#####################################################################
### Extension helper ###
#####################################################################
from mercurial import (
commands,
+ error,
extensions,
registrar,
- revset,
- templatekw,
- util,
)
-configitem = None
-dynamicdefault = None
-if util.safehasattr(registrar, 'configitem'):
- configitem = registrar.configitem
- from mercurial import configitems
- dynamicdefault = configitems.dynamicdefault
-
class exthelper(object):
"""Helper for modular extension setup
- A single helper should be instantiated for each extension. Helper
- methods are then used as decorators for various purpose.
+ A single helper should be instantiated for each module of an
+ extension, where a command or function needs to be wrapped, or a
+ command, extension hook, fileset, revset or template needs to be
+ registered. Helper methods are then used as decorators for
+ these various purposes. If an extension spans multiple modules,
+ all helper instances should be merged in the main module.
All decorators return the original function and may be chained.
+
+ Aside from the helper functions with examples below, several
+ registrar method aliases are available for adding commands,
+ configitems, filesets, revsets, and templates. Simply decorate
+ the appropriate methods, and assign the corresponding exthelper
+ variable to a module level variable of the extension. The
+ extension loading mechanism will handle the rest.
+
+ example::
+
+ # ext.py
+ eh = exthelper.exthelper()
+
+ # As needed:
+ cmdtable = eh.cmdtable
+ configtable = eh.configtable
+ filesetpredicate = eh.filesetpredicate
+ revsetpredicate = eh.revsetpredicate
+ templatekeyword = eh.templatekeyword
+
+ @eh.command('mynewcommand',
+ [('r', 'rev', [], _('operate on these revisions'))],
+ _('-r REV...'),
+ helpcategory=command.CATEGORY_XXX)
+ def newcommand(ui, repo, *revs, **opts):
+ # implementation goes here
+
+ eh.configitem('experimental', 'foo',
+ default=False,
+ )
+
+ @eh.filesetpredicate('lfs()')
+ def filesetbabar(mctx, x):
+ return mctx.predicate(...)
+
+ @eh.revsetpredicate('hidden')
+ def revsetbabar(repo, subset, x):
+ args = revset.getargs(x, 0, 0, 'babar accept no argument')
+ return [r for r in subset if 'babar' in repo[r].description()]
+
+ @eh.templatekeyword('babar')
+ def kwbabar(ctx):
+ return 'babar'
"""
def __init__(self):
+ self._uipopulatecallables = []
self._uicallables = []
self._extcallables = []
self._repocallables = []
- self._revsetsymbols = []
- self._templatekws = []
self._commandwrappers = []
self._extcommandwrappers = []
self._functionwrappers = []
@@ -49,27 +93,19 @@
self.command._doregister = _newdoregister
self.configtable = {}
- self._configitem = None
- if configitem is not None:
- self._configitem = configitem(self.configtable)
-
- def configitem(self, section, config):
- """For Mercurial 4.4 and above, register a config item
-
- For now constraint to 'dynamicdefault' until we only support version with the feature.
- Older version would otherwise not use the declare default.
-
- For older version no-op fallback for old Mercurial versions
- """
- if self._configitem is not None:
- self._configitem(section, config, default=dynamicdefault)
+ self.configitem = registrar.configitem(self.configtable)
+ self.filesetpredicate = registrar.filesetpredicate()
+ self.revsetpredicate = registrar.revsetpredicate()
+ self.templatekeyword = registrar.templatekeyword()
def merge(self, other):
self._uicallables.extend(other._uicallables)
+ self._uipopulatecallables.extend(other._uipopulatecallables)
self._extcallables.extend(other._extcallables)
self._repocallables.extend(other._repocallables)
- self._revsetsymbols.extend(other._revsetsymbols)
- self._templatekws.extend(other._templatekws)
+ self.filesetpredicate._table.update(other.filesetpredicate._table)
+ self.revsetpredicate._table.update(other.revsetpredicate._table)
+ self.templatekeyword._table.update(other.templatekeyword._table)
self._commandwrappers.extend(other._commandwrappers)
self._extcommandwrappers.extend(other._extcommandwrappers)
self._functionwrappers.extend(other._functionwrappers)
@@ -81,7 +117,7 @@
else:
self.configtable[section] = items
- def final_uisetup(self, ui):
+ def finaluisetup(self, ui):
"""Method to be used as the extension uisetup
The following operations belong here:
@@ -105,14 +141,26 @@
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 opt in opts:
+ entry[1].append(opt)
for cont, funcname, wrapper in self._functionwrappers:
extensions.wrapfunction(cont, funcname, wrapper)
for c in self._uicallables:
c(ui)
- def final_extsetup(self, ui):
+ def finaluipopulate(self, ui):
+ """Method to be used as the extension uipopulate
+
+ This is called once per ui instance to:
+
+ - Set up additional ui members
+ - Update configuration by ``ui.setconfig()``
+ - Extend the class dynamically
+ """
+ for c in self._uipopulatecallables:
+ c(ui)
+
+ def finalextsetup(self, ui):
"""Method to be used as a the extension extsetup
The following operations belong here:
@@ -120,23 +168,9 @@
- Changes depending on the status of other extensions. (if
extensions.find('mq'))
- Add a global option to all commands
- - Register revset functions
"""
knownexts = {}
- revsetpredicate = registrar.revsetpredicate()
- for name, symbol in self._revsetsymbols:
- revsetpredicate(name)(symbol)
- revset.loadpredicate(ui, 'evolve', revsetpredicate)
-
- templatekeyword = registrar.templatekeyword()
- for name, kw, requires in self._templatekws:
- if requires is not None:
- templatekeyword(name, requires=requires)(kw)
- else:
- templatekeyword(name)(kw)
- templatekw.loadkeyword(ui, 'evolve', templatekeyword)
-
for ext, command, wrapper, opts in self._extcommandwrappers:
if ext not in knownexts:
try:
@@ -148,13 +182,13 @@
knownexts[ext] = e.cmdtable
entry = extensions.wrapcommand(knownexts[ext], command, wrapper)
if opts:
- for short, long, val, msg in opts:
- entry[1].append((short, long, val, msg))
+ for opt in opts:
+ entry[1].append(opt)
for c in self._extcallables:
c(ui)
- def final_reposetup(self, ui, repo):
+ def finalreposetup(self, ui, repo):
"""Method to be used as the extension reposetup
The following operations belong here:
@@ -178,6 +212,18 @@
self._uicallables.append(call)
return call
+ def uipopulate(self, call):
+ """Decorated function will be executed during uipopulate
+
+ example::
+
+ @eh.uipopulate
+ def setupfoo(ui):
+ print 'this is uipopulate!'
+ """
+ self._uipopulatecallables.append(call)
+ return call
+
def extsetup(self, call):
"""Decorated function will be executed during extsetup
@@ -202,42 +248,7 @@
self._repocallables.append(call)
return call
- def revset(self, symbolname):
- """Decorated function is a revset symbol
-
- The name of the symbol must be given as the decorator argument.
- The symbol is added during `extsetup`.
-
- example::
-
- @eh.revset('hidden')
- def revsetbabar(repo, subset, x):
- args = revset.getargs(x, 0, 0, 'babar accept no argument')
- return [r for r in subset if 'babar' in repo[r].description()]
- """
- def dec(symbol):
- self._revsetsymbols.append((symbolname, symbol))
- return symbol
- return dec
-
- def templatekw(self, keywordname, requires=None):
- """Decorated function is a template keyword
-
- The name of the keyword must be given as the decorator argument.
- The symbol is added during `extsetup`.
-
- example::
-
- @eh.templatekw('babar')
- def kwbabar(ctx):
- return 'babar'
- """
- def dec(keyword):
- self._templatekws.append((keywordname, keyword, requires))
- return keyword
- return dec
-
- def wrapcommand(self, command, extension=None, opts=[]):
+ def wrapcommand(self, command, extension=None, opts=None):
"""Decorated function is a command wrapper
The name of the command must be given as the decorator argument.
@@ -256,10 +267,21 @@
ui.note('Barry!')
return orig(ui, repo, *args, **kwargs)
- The `opts` argument allows specifying additional arguments for the
- command.
+ The `opts` argument allows specifying a list of tuples for additional
+ arguments for the command. See ``mercurial.fancyopts.fancyopts()`` for
+ the format of the tuple.
"""
+ if opts is None:
+ opts = []
+ else:
+ for opt in opts:
+ if not isinstance(opt, tuple):
+ raise error.ProgrammingError('opts must be list of tuples')
+ if len(opt) not in (4, 5):
+ msg = 'each opt tuple must contain 4 or 5 values'
+ raise error.ProgrammingError(msg)
+
def dec(wrapper):
if extension is None:
self._commandwrappers.append((command, wrapper, opts))
@@ -294,9 +316,18 @@
This function takes two arguments, the container and the name of the
function to wrap. The wrapping is performed during `uisetup`.
+ Adding attributes to a container like this is discouraged, because the
+ container modification is visible even in repositories that do not
+ have the extension loaded. Therefore, care must be taken that the
+ function doesn't make assumptions that the extension was loaded for the
+ current repository. For `ui` and `repo` instances, a better option is
+ to subclass the instance in `uipopulate` and `reposetup` respectively.
+
+ https://www.mercurial-scm.org/wiki/WritingExtensions
+
example::
- @eh.function(context.changectx, 'babar')
+ @eh.addattr(context.changectx, 'babar')
def babar(ctx):
return 'babar' in ctx.description
"""
--- a/hgext3rd/evolve/firstmergecache.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/firstmergecache.py Tue Jan 22 10:46:02 2019 -0500
@@ -75,8 +75,8 @@
total = len(data)
def progress(pos, rev):
- repo.ui.progress('updating firstmerge cache',
- pos, 'rev %s' % rev, unit='revision', total=total)
+ compat.progress(repo.ui, 'updating firstmerge cache',
+ pos, 'rev %s' % rev, unit='revision', total=total)
progress(0, '')
for idx, rev in enumerate(data, 1):
assert rev == len(self._data), (rev, len(self._data))
--- a/hgext3rd/evolve/metadata.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/metadata.py Tue Jan 22 10:46:02 2019 -0500
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-__version__ = '8.3.4.dev'
-testedwith = '4.3.2 4.4.2 4.5.2 4.6.2 4.7 4.8'
-minimumhgversion = '4.3'
+__version__ = '8.4.0.dev'
+testedwith = '4.4.2 4.5.2 4.6.2 4.7 4.8 4.9'
+minimumhgversion = '4.4'
buglink = 'https://bz.mercurial-scm.org/'
--- a/hgext3rd/evolve/obsdiscovery.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/obsdiscovery.py Tue Jan 22 10:46:02 2019 -0500
@@ -74,11 +74,11 @@
obsexcmsg = utility.obsexcmsg
# Config
-eh.configitem('experimental', 'evolution.obsdiscovery')
-eh.configitem('experimental', 'obshashrange')
-eh.configitem('experimental', 'obshashrange.warm-cache')
-eh.configitem('experimental', 'obshashrange.max-revs')
-eh.configitem('experimental', 'obshashrange.lru-size')
+eh.configitem('experimental', 'evolution.obsdiscovery', True)
+eh.configitem('experimental', 'obshashrange', True)
+eh.configitem('experimental', 'obshashrange.warm-cache', 'auto')
+eh.configitem('experimental', 'obshashrange.max-revs', None)
+eh.configitem('experimental', 'obshashrange.lru-size', 2000)
##################################
### Code performing discovery ###
@@ -95,8 +95,8 @@
common = set()
undecided = set(probeset)
totalnb = len(undecided)
- ui.progress(_("comparing with other"), 0, total=totalnb,
- unit=_("changesets"))
+ compat.progress(ui, _("comparing with other"), 0, total=totalnb,
+ unit=_("changesets"))
_takefullsample = setdiscovery._takefullsample
if remote.capable('_evoext_obshash_1'):
getremotehash = remote.evoext_obshash1
@@ -120,8 +120,8 @@
sample = _takefullsample(dag, undecided, size=fullsamplesize)
roundtrips += 1
- ui.progress(_("comparing with other"), totalnb - len(undecided),
- total=totalnb, unit=_("changesets"))
+ compat.progress(ui, _("comparing with other"), totalnb - len(undecided),
+ total=totalnb, unit=_("changesets"))
ui.debug("query %i; still undecided: %i, sample size is: %i\n"
% (roundtrips, len(undecided), len(sample)))
# indices between sample and externalized version must match
@@ -140,7 +140,7 @@
undecided.difference_update(missing)
undecided.difference_update(common)
- ui.progress(_("comparing with other"), None)
+ compat.progress(ui, _("comparing with other"), None)
result = dag.headsetofconnecteds(common)
ui.debug("%d total queries\n" % roundtrips)
@@ -182,8 +182,8 @@
local.obsstore.rangeobshashcache.update(local)
querycount = 0
- ui.progress(_("comparing obsmarker with other"), querycount,
- unit=_("queries"))
+ compat.progress(ui, _("comparing obsmarker with other"), querycount,
+ unit=_("queries"))
overflow = []
while sample or overflow:
if overflow:
@@ -238,9 +238,9 @@
addentry(new)
assert nbsample == nbreplies
querycount += 1
- ui.progress(_("comparing obsmarker with other"), querycount,
- unit=_("queries"))
- ui.progress(_("comparing obsmarker with other"), None)
+ compat.progress(ui, _("comparing obsmarker with other"), querycount,
+ unit=_("queries"))
+ compat.progress(ui, _("comparing obsmarker with other"), None)
local.obsstore.rangeobshashcache.save(local)
duration = util.timer() - starttime
logmsg = ('obsdiscovery, %d/%d mismatch'
@@ -545,8 +545,8 @@
total = len(revs)
def progress(pos, rev):
- repo.ui.progress('updating obshashrange cache',
- pos, 'rev %s' % rev, unit='revision', total=total)
+ compat.progress(repo.ui, 'updating obshashrange cache',
+ pos, 'rev %s' % rev, unit='revision', total=total)
# warm the cache for the new revs
progress(0, '')
for idx, r in enumerate(revs):
@@ -775,9 +775,9 @@
return encodelist(hashes)
def _useobshashrange(repo):
- base = repo.ui.configbool('experimental', 'obshashrange', True)
+ base = repo.ui.configbool('experimental', 'obshashrange')
if base:
- maxrevs = repo.ui.configint('experimental', 'obshashrange.max-revs', None)
+ maxrevs = repo.ui.configint('experimental', 'obshashrange.max-revs')
if maxrevs is not None and maxrevs < len(repo.unfiltered()):
base = False
return base
@@ -861,8 +861,8 @@
cache = []
unfi = repo.unfiltered()
markercache = {}
- repo.ui.progress(_("preparing locally"), 0, total=len(unfi),
- unit=_("changesets"))
+ compat.progress(repo.ui, _("preparing locally"), 0, total=len(unfi),
+ unit=_("changesets"))
for i in unfi:
ctx = unfi[i]
entry = 0
@@ -892,9 +892,9 @@
cache.append((ctx.node(), sha.digest()))
else:
cache.append((ctx.node(), node.nullid))
- repo.ui.progress(_("preparing locally"), i, total=len(unfi),
- unit=_("changesets"))
- repo.ui.progress(_("preparing locally"), None)
+ compat.progress(repo.ui, _("preparing locally"), i, total=len(unfi),
+ unit=_("changesets"))
+ compat.progress(repo.ui, _("preparing locally"), None)
return cache
def _obshash(repo, nodes, version=0):
@@ -945,7 +945,7 @@
"""wrapper to advertise new capability"""
caps = orig(repo, proto)
if (obsolete.isenabled(repo, obsolete.exchangeopt)
- and repo.ui.configbool('experimental', 'evolution.obsdiscovery', True)):
+ and repo.ui.configbool('experimental', 'evolution.obsdiscovery')):
# Compat hg 4.6+ (2f7290555c96)
bytesresponse = False
@@ -1015,7 +1015,7 @@
"""
def usediscovery(repo):
- return repo.ui.configbool('experimental', 'evolution.obsdiscovery', True)
+ return repo.ui.configbool('experimental', 'evolution.obsdiscovery')
@eh.wrapfunction(exchange, '_pushdiscoveryobsmarkers')
def _pushdiscoveryobsmarkers(orig, pushop):
@@ -1088,12 +1088,12 @@
if bundle2 and _canobshashrange(repo, remote):
obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
% len(revs))
- boundaries['missing'] = findmissingrange(repo.ui, repo, pullop.remote,
+ boundaries['missing'] = findmissingrange(repo.ui, unfi, pullop.remote,
revs)
elif remote.capable('_evoext_obshash_0'):
obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
% len(revs))
- boundaries['common'] = findcommonobsmarkers(repo.ui, repo, remote, revs)
+ boundaries['common'] = findcommonobsmarkers(repo.ui, unfi, remote, revs)
else:
boundaries['common'] = [node.nullid]
return boundaries
--- a/hgext3rd/evolve/obsexchange.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/obsexchange.py Tue Jan 22 10:46:02 2019 -0500
@@ -39,7 +39,7 @@
obsexcmsg = utility.obsexcmsg
obsexcprg = utility.obsexcprg
-eh.configitem('experimental', 'verbose-obsolescence-exchange')
+eh.configitem('experimental', 'verbose-obsolescence-exchange', False)
_bestformat = max(obsolete.formats.keys())
--- a/hgext3rd/evolve/obshistory.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/obshistory.py Tue Jan 22 10:46:02 2019 -0500
@@ -14,7 +14,6 @@
error,
graphmod,
patch,
- obsolete,
obsutil,
node as nodemod,
scmutil,
@@ -863,49 +862,6 @@
return False
return True
-# Wrap pre Mercurial 4.4 createmarkers that didn't included effect-flag
-if not util.safehasattr(obsutil, 'geteffectflag'):
- @eh.wrapfunction(obsolete, 'createmarkers')
- def createmarkerswithbits(orig, repo, relations, flag=0, date=None,
- metadata=None, **kwargs):
- """compute 'effect-flag' and augment the created markers
-
- Wrap obsolete.createmarker in order to compute the effect of each
- relationship and store them as flag in the metadata.
-
- While we experiment, we store flag in a metadata field. This field is
- "versionned" to easilly allow moving to other meaning for flags.
-
- The comparison of description or other infos just before creating the obs
- marker might induce overhead in some cases. However it is a good place to
- start since it automatically makes all markers creation recording more
- meaningful data. In the future, we can introduce way for commands to
- provide precomputed effect to avoid the overhead.
- """
- if not repo.ui.configbool('experimental', 'evolution.effect-flags', **efd):
- return orig(repo, relations, flag, date, metadata, **kwargs)
- if metadata is None:
- metadata = {}
- tr = repo.transaction('add-obsolescence-marker')
- try:
- for r in relations:
- # Compute the effect flag for each obsmarker
- effect = geteffectflag(r)
-
- # Copy the metadata in order to add them, we copy because the
- # effect flag might be different per relation
- m = metadata.copy()
- # we store the effect even if "0". This disctinct markers created
- # without the feature with markers recording a no-op.
- m['ef1'] = "%d" % effect
-
- # And call obsolete.createmarkers for creating the obsmarker for real
- orig(repo, [r], flag, date, m, **kwargs)
-
- tr.close()
- finally:
- tr.release()
-
def _getobsfate(successorssets):
""" Compute a changeset obsolescence fate based on his successorssets.
Successors can be the tipmost ones or the immediate ones.
--- a/hgext3rd/evolve/rewind.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/rewind.py Tue Jan 22 10:46:02 2019 -0500
@@ -27,10 +27,11 @@
@eh.command(
'rewind|undo',
- [('', 'to', [], _("rewind to these revisions")),
+ [('', 'to', [], _("rewind to these revisions"), _('REV')),
('', 'as-divergence', None, _("preserve current latest successors")),
('', 'exact', None, _("only rewind explicitly selected revisions")),
- ('', 'from', [], _("rewind these revisions to their predecessors")),
+ ('', 'from', [],
+ _("rewind these revisions to their predecessors"), _('REV')),
],
_(''),
helpbasic=True)
--- a/hgext3rd/evolve/safeguard.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/safeguard.py Tue Jan 22 10:46:02 2019 -0500
@@ -8,37 +8,48 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from mercurial import error
+from mercurial.i18n import _
-from mercurial.i18n import _
+from mercurial import (
+ configitems,
+ error,
+)
from . import exthelper
eh = exthelper.exthelper()
-eh.configitem('experimental', 'auto-publish')
+# hg <= 4.8
+if 'auto-publish' not in configitems.coreitems.get('experimental', {}):
+
+ eh.configitem('experimental', 'auto-publish', 'publish')
-@eh.reposetup
-def setuppublishprevention(ui, repo):
+ @eh.reposetup
+ def setuppublishprevention(ui, repo):
- class noautopublishrepo(repo.__class__):
+ class noautopublishrepo(repo.__class__):
- def checkpush(self, pushop):
- super(noautopublishrepo, self).checkpush(pushop)
- behavior = self.ui.config('experimental', 'auto-publish', 'default')
- remotephases = pushop.remote.listkeys('phases')
- publishing = remotephases.get('publishing', False)
- if behavior in ('warn', 'abort') and publishing:
- if pushop.revs is None:
- published = self.filtered('served').revs("not public()")
- else:
- published = self.revs("::%ln - public()", pushop.revs)
- if published:
- if behavior == 'warn':
- self.ui.warn(_('%i changesets about to be published\n') % len(published))
- elif behavior == 'abort':
- msg = _('push would publish 1 changesets')
- hint = _("behavior controlled by 'experimental.auto-publish' config")
- raise error.Abort(msg, hint=hint)
+ def checkpush(self, pushop):
+ super(noautopublishrepo, self).checkpush(pushop)
+ behavior = self.ui.config('experimental', 'auto-publish')
+ nocheck = behavior not in ('warn', 'abort')
+ if nocheck or getattr(pushop, 'publish', False):
+ return
+ remotephases = pushop.remote.listkeys('phases')
+ publishing = remotephases.get('publishing', False)
+ if publishing:
+ if pushop.revs is None:
+ published = self.filtered('served').revs("not public()")
+ else:
+ published = self.revs("::%ln - public()", pushop.revs)
+ if published:
+ if behavior == 'warn':
+ self.ui.warn(_('%i changesets about to be published\n')
+ % len(published))
+ elif behavior == 'abort':
+ msg = _('push would publish 1 changesets')
+ hint = _("behavior controlled by "
+ "'experimental.auto-publish' config")
+ raise error.Abort(msg, hint=hint)
- repo.__class__ = noautopublishrepo
+ repo.__class__ = noautopublishrepo
--- a/hgext3rd/evolve/serveronly.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/serveronly.py Tue Jan 22 10:46:02 2019 -0500
@@ -45,9 +45,9 @@
eh.merge(compat.eh)
eh.merge(obscache.eh)
eh.merge(obsexchange.eh)
-uisetup = eh.final_uisetup
-extsetup = eh.final_extsetup
-reposetup = eh.final_reposetup
+uisetup = eh.finaluisetup
+extsetup = eh.finalextsetup
+reposetup = eh.finalreposetup
cmdtable = eh.cmdtable
configtable = eh.configtable
--- a/hgext3rd/evolve/stablerange.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/stablerange.py Tue Jan 22 10:46:02 2019 -0500
@@ -23,6 +23,7 @@
from mercurial.i18n import _
from . import (
+ compat,
exthelper,
firstmergecache,
stablesort,
@@ -619,12 +620,12 @@
rangeheap = []
for idx, r in enumerate(revs):
if not idx % 1000:
- ui.progress(_("filling depth cache"), idx, total=nbrevs,
- unit=_("changesets"))
+ compat.progress(ui, _("filling depth cache"), idx, total=nbrevs,
+ unit=_("changesets"))
# warm up depth
self.depthrev(repo, r)
rangeheap.append((-r, (r, 0)))
- ui.progress(_("filling depth cache"), None, total=nbrevs)
+ compat.progress(ui, _("filling depth cache"), None, total=nbrevs)
heappop = heapq.heappop
heappush = heapq.heappush
@@ -645,8 +646,8 @@
progress_new = time.time()
if (1 < progress_each) and (0.1 < progress_new - progress_last):
progress_each /= 10
- ui.progress(_("filling stablerange cache"), seen,
- total=nbrevs, unit=_("changesets"))
+ compat.progress(ui, _("filling stablerange cache"), seen,
+ total=nbrevs, unit=_("changesets"))
progress_last = progress_new
seen += 1
original.remove(value) # might have been added from other source
@@ -655,7 +656,7 @@
for sub in self.subranges(repo, rangeid):
if self._getsub(sub) is None:
heappush(rangeheap, (-sub[0], sub))
- ui.progress(_("filling stablerange cache"), None, total=nbrevs)
+ compat.progress(ui, _("filling stablerange cache"), None, total=nbrevs)
self._tiprev = upto
self._tipnode = cl.node(upto)
--- a/hgext3rd/evolve/stablerangecache.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/stablerangecache.py Tue Jan 22 10:46:02 2019 -0500
@@ -21,6 +21,7 @@
)
from . import (
+ compat,
exthelper,
genericcaches,
stablerange,
@@ -97,8 +98,8 @@
warned_long = True
if (1 < progress_each) and (0.1 < progress_new - progress_last):
progress_each /= 10
- ui.progress(_("filling stablerange cache"), seen,
- total=total, unit=_("changesets"))
+ compat.progress(ui, _("filling stablerange cache"), seen,
+ total=total, unit=_("changesets"))
progress_last = progress_new
seen += 1
original.remove(rangeid) # might have been added from other source
@@ -107,7 +108,7 @@
for sub in self.subranges(repo, rangeid):
if self._getsub(sub) is None:
heappush(rangeheap, sub)
- ui.progress(_("filling stablerange cache"), None, total=total)
+ compat.progress(ui, _("filling stablerange cache"), None, total=total)
def clear(self, reset=False):
super(stablerangeondiskbase, self).clear()
--- a/hgext3rd/evolve/stablesort.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/stablesort.py Tue Jan 22 10:46:02 2019 -0500
@@ -577,8 +577,8 @@
total = len(data)
def progress(pos, rev):
- repo.ui.progress('updating stablesort cache',
- pos, 'rev %s' % rev, unit='revision', total=total)
+ compat.progress(repo.ui, 'updating stablesort cache',
+ pos, 'rev %s' % rev, unit='revision', total=total)
progress(0, '')
for idx, rev in enumerate(data):
--- a/hgext3rd/evolve/templatekw.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/templatekw.py Tue Jan 22 10:46:02 2019 -0500
@@ -9,7 +9,6 @@
"""
from . import (
- compat,
error,
exthelper,
obshistory
@@ -17,7 +16,6 @@
from mercurial import (
templatekw,
- node,
util
)
@@ -26,14 +24,14 @@
### template keywords
if util.safehasattr(templatekw, 'compatlist'):
- @eh.templatekw('troubles', requires=set(['ctx', 'templ']))
+ @eh.templatekeyword('troubles', requires=set(['ctx', 'templ']))
def showtroubles(context, mapping):
ctx = context.resource(mapping, 'ctx')
return templatekw.compatlist(context, mapping, 'trouble',
ctx.instabilities(), plural='troubles')
else:
# older template API in hg < 4.6
- @eh.templatekw('troubles')
+ @eh.templatekeyword('troubles')
def showtroubles(**args):
"""List of strings. Evolution troubles affecting the changeset
(zero or more of "unstable", "divergent" or "bumped")."""
@@ -41,79 +39,14 @@
return templatekw.showlist('trouble', ctx.instabilities(), args,
plural='troubles')
-if util.safehasattr(templatekw, 'showpredecessors'):
- templatekw.keywords["precursors"] = templatekw.showpredecessors
-else:
- # for version <= hg4.3
- def closestprecursors(repo, nodeid):
- """ Yield the list of next precursors pointing on visible changectx nodes
- """
-
- precursors = repo.obsstore.predecessors
- stack = [nodeid]
- seen = set(stack)
-
- while stack:
- current = stack.pop()
- currentpreccs = precursors.get(current, ())
-
- for prec in currentpreccs:
- precnodeid = prec[0]
-
- # Basic cycle protection
- if precnodeid in seen:
- continue
- seen.add(precnodeid)
-
- if precnodeid in repo:
- yield precnodeid
- else:
- stack.append(precnodeid)
-
- @eh.templatekw("precursors")
- def shownextvisibleprecursors(repo, ctx, **args):
- """Returns a string containing the list of the closest precursors
- """
- precursors = sorted(closestprecursors(repo, ctx.node()))
- precursors = [node.hex(p) for p in precursors]
-
- return templatekw._hybrid(None, precursors, lambda x: {'precursor': x},
- lambda d: d['precursor'][:12])
+templatekw.keywords["precursors"] = templatekw.showpredecessors
def closestsuccessors(repo, nodeid):
""" returns the closest visible successors sets instead.
"""
return directsuccessorssets(repo, nodeid)
-if util.safehasattr(templatekw, 'showsuccessorssets'):
- templatekw.keywords["successors"] = templatekw.showsuccessorssets
-else:
- # for version <= hg4.3
-
- @eh.templatekw("successors")
- def shownextvisiblesuccessors(repo, ctx, templ, **args):
- """Returns a string of sets of successors for a changectx
-
- Format used is: [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and
- ctx2 while also diverged into ctx3"""
- if not ctx.obsolete():
- return ''
-
- ssets, _ = closestsuccessors(repo, ctx.node())
- ssets = [[node.hex(n) for n in ss] for ss in ssets]
-
- data = []
- gen = []
- for ss in ssets:
- subgen = '[%s]' % ', '.join(n[:12] for n in ss)
- gen.append(subgen)
- h = templatekw._hybrid(iter(subgen), ss, lambda x: {'successor': x},
- lambda d: "%s" % d["successor"])
- data.append(h)
-
- gen = ', '.join(gen)
- return templatekw._hybrid(iter(gen), data, lambda x: {'successorset': x},
- lambda d: d["successorset"])
+templatekw.keywords["successors"] = templatekw.showsuccessorssets
def _getusername(ui):
"""the default username in the config or None"""
@@ -241,25 +174,8 @@
return "\n".join(lines)
-if util.safehasattr(templatekw, 'obsfateverb'):
- # Individuals fragments are available in core
- pass
-elif util.safehasattr(templatekw, 'compatlist'):
- @eh.templatekw('obsfatedata', requires=set(['ctx', 'templ']))
- def showobsfatedata(context, mapping):
- ctx = context.resource(mapping, 'ctx')
- repo = ctx.repo()
- values = obsfatedata(repo, ctx)
-
- if values is None:
- return templatekw.compatlist(context, mapping, "obsfatedata", [])
- args = mapping.copy()
- args.pop('ctx')
- args['templ'] = context
- return _showobsfatedata(repo, ctx, values, **args)
-else:
- # pre hg-4.6
- @eh.templatekw("obsfatedata")
+if not util.safehasattr(templatekw, 'obsfateverb'): # <= hg-4.5
+ @eh.templatekeyword("obsfatedata")
def showobsfatedata(repo, ctx, **args):
# Get the needed obsfate data
values = obsfatedata(repo, ctx)
@@ -325,30 +241,6 @@
return templatekw._hybrid(gen, values, lambda x: {name: x}, fmt)
-# rely on core mercurial starting from 4.4 for the obsfate template
-if not util.safehasattr(templatekw, 'showobsfate'):
-
- @eh.templatekw("obsfate")
- def showobsfate(*args, **kwargs):
- return showobsfatedata(*args, **kwargs)
-
-if util.safehasattr(compat.changesetprinter, '_showobsfate'):
- pass # already included by default
-elif util.safehasattr(compat.changesetprinter, '_exthook'):
- @eh.wrapfunction(compat.changesetprinter, '_exthook')
- def exthook(original, self, ctx):
- # Call potential other extensions
- original(self, ctx)
-
- obsfate = obsfatedata(self.repo, ctx)
- if obsfate is None:
- return ""
-
- output = obsfateprinter(obsfate, self.ui, prefix="obsolete: ")
-
- self.ui.write(output, label='log.obsfate')
- self.ui.write("\n")
-
# copy from mercurial.obsolete with a small change to stop at first known changeset.
def directsuccessorssets(repo, initialnode, cache=None):
--- a/hgext3rd/evolve/utility.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/evolve/utility.py Tue Jan 22 10:46:02 2019 -0500
@@ -13,12 +13,15 @@
from mercurial.node import nullrev
+from . import (
+ compat,
+)
+
shorttemplate = "[{label('evolve.rev', rev)}] {desc|firstline}\n"
stacktemplate = """[{label('evolve.rev', if(topicidx, "s{topicidx}", rev))}] {desc|firstline}\n"""
def obsexcmsg(ui, message, important=False):
- verbose = ui.configbool('experimental', 'verbose-obsolescence-exchange',
- False)
+ verbose = ui.configbool('experimental', 'verbose-obsolescence-exchange')
if verbose:
message = 'OBSEXC: ' + message
if important or verbose:
@@ -26,9 +29,9 @@
def obsexcprg(ui, *args, **kwargs):
topic = 'obsmarkers exchange'
- if ui.configbool('experimental', 'verbose-obsolescence-exchange', False):
+ if ui.configbool('experimental', 'verbose-obsolescence-exchange'):
topic = 'OBSEXC'
- ui.progress(topic, *args, **kwargs)
+ compat.progress(ui, topic, *args, **kwargs)
def filterparents(parents):
"""filter nullrev parents
@@ -63,12 +66,12 @@
warm = autocase
else:
# note: we should not get to the default case
- warm = configbool('experimental', 'obshashrange.warm-cache', True)
- if not configbool('experimental', 'obshashrange', True):
+ warm = configbool('experimental', 'obshashrange.warm-cache')
+ if not configbool('experimental', 'obshashrange'):
return False
if not warm:
return False
- maxrevs = repo.ui.configint('experimental', 'obshashrange.max-revs', None)
+ maxrevs = repo.ui.configint('experimental', 'obshashrange.max-revs')
if maxrevs is not None and maxrevs < len(repo.unfiltered()):
return False
return True
--- a/hgext3rd/topic/__init__.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/topic/__init__.py Tue Jan 22 10:46:02 2019 -0500
@@ -177,10 +177,10 @@
'topic.active': 'green',
}
-__version__ = '0.12.4.dev'
+__version__ = '0.13.0.dev'
-testedwith = '4.3.3 4.4.2 4.5.2 4.6.2 4.7 4.8'
-minimumhgversion = '4.3'
+testedwith = '4.4.2 4.5.2 4.6.2 4.7 4.8'
+minimumhgversion = '4.4'
buglink = 'https://bz.mercurial-scm.org/'
if util.safehasattr(registrar, 'configitem'):
@@ -680,7 +680,11 @@
txn = repo.transaction('rewrite-topics')
rewrote = _changetopics(ui, repo, touchedrevs, topic)
txn.close()
- ui.status('changed topic on %d changes\n' % rewrote)
+ if topic is None:
+ ui.status('cleared topic on %d changesets\n' % rewrote)
+ else:
+ ui.status('changed topic on %d changesets to "%s"\n' % (rewrote,
+ topic))
finally:
lockmod.release(txn, lock, wl)
repo.invalidate()
@@ -717,6 +721,8 @@
return ret
@command('stack', [
+ ('c', 'children', None,
+ _('display data about children outside of the stack'))
] + commands.formatteropts,
_('hg stack [TOPIC]'))
def cmdstack(ui, repo, topic='', **opts):
@@ -950,17 +956,21 @@
def _listtopics(ui, repo, opts):
fm = ui.formatter('topics', opts)
- showlast = opts.get('age')
- if showlast:
- # we have a new function as plugging logic into existing function is
- # pretty much difficult
- return _showlasttouched(repo, fm, opts)
activetopic = repo.currenttopic
namemask = '%s'
if repo.topics:
maxwidth = max(len(t) for t in repo.topics)
namemask = '%%-%is' % maxwidth
- for topic in sorted(repo.topics):
+ if opts.get('age'):
+ # here we sort by age and topic name
+ topicsdata = sorted(_getlasttouched(repo, repo.topics))
+ else:
+ # here we sort by topic name only
+ topicsdata = (
+ (None, topic, None, None)
+ for topic in sorted(repo.topics)
+ )
+ for age, topic, date, user in topicsdata:
fm.startitem()
marker = ' '
label = 'topic'
@@ -977,8 +987,18 @@
if ui.quiet:
fm.plain('\n')
continue
+ fm.plain(' (')
+ if date:
+ if age == -1:
+ timestr = 'empty and active'
+ else:
+ timestr = templatefilters.age(date)
+ fm.write('lasttouched', '%s', timestr, label='topic.list.time')
+ if user:
+ fm.write('usertouched', ' by %s', user, label='topic.list.user')
+ if date:
+ fm.plain(', ')
data = stack.stack(repo, topic=topic)
- fm.plain(' (')
if ui.verbose:
fm.write('branches+', 'on branch: %s',
'+'.join(data.branches), # XXX use list directly after 4.0 is released
@@ -1018,52 +1038,17 @@
fm.plain(')\n')
fm.end()
-def _showlasttouched(repo, fm, opts):
- topics = repo.topics
- timedict = _getlasttouched(repo, topics)
- times = timedict.keys()
- times.sort()
- if topics:
- maxwidth = max(len(t) for t in topics)
- namemask = '%%-%is' % maxwidth
- activetopic = repo.currenttopic
- for timevalue in times:
- curtopics = sorted(timedict[timevalue][1])
- for topic, user in curtopics:
- fm.startitem()
- marker = ' '
- label = 'topic'
- active = (topic == activetopic)
- if active:
- marker = '*'
- label = 'topic.active'
- fm.plain(' %s ' % marker, label=label)
- fm.write('topic', namemask, topic, label=label)
- fm.data(active=active)
- fm.plain(' (')
- if timevalue == -1:
- timestr = 'empty and active'
- else:
- timestr = templatefilters.age(timedict[timevalue][0])
- fm.write('lasttouched', '%s', timestr, label='topic.list.time')
- if user:
- fm.write('usertouched', ' by %s', user, label='topic.list.user')
- fm.plain(')')
- fm.plain('\n')
- fm.end()
-
def _getlasttouched(repo, topics):
"""
- Calculates the last time a topic was used. Returns a dictionary of seconds
- passed from current time for a topic as keys and topic name as values.
+ Calculates the last time a topic was used. Returns a generator of 4-tuples:
+ (age in seconds, topic name, date, and user who last touched the topic).
"""
- topicstime = {}
curtime = time.time()
- for t in topics:
- secspassed = -1
+ for topic in topics:
+ age = -1
user = None
maxtime = (0, 0)
- trevs = repo.revs("topic(%s)", t)
+ trevs = repo.revs("topic(%s)", topic)
# Need to check for the time of all changesets in the topic, whether
# they are obsolete of non-heads
# XXX: can we just rely on the max rev number for this
@@ -1084,16 +1069,10 @@
maxtime = rt
username = stack.parseusername(user)
- topicuser = (t, username)
+ if trevs:
+ age = curtime - maxtime[0]
- if trevs:
- secspassed = (curtime - maxtime[0])
- try:
- topicstime[secspassed][1].append(topicuser)
- except KeyError:
- topicstime[secspassed] = (maxtime, [topicuser])
-
- return topicstime
+ yield (age, topic, maxtime, username)
def summaryhook(ui, repo):
t = getattr(repo, 'currenttopic', '')
--- a/hgext3rd/topic/discovery.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/topic/discovery.py Tue Jan 22 10:46:02 2019 -0500
@@ -33,32 +33,30 @@
publishedset = ()
remotebranchmap = None
origremotebranchmap = remote.branchmap
- # < hg-4.4 do not have a --publish flag anyway
- if util.safehasattr(pushop, 'remotephases'):
- publishednode = [c.node() for c in pushop.outdatedphases]
- publishedset = repo.revs('ancestors(%ln + %ln)',
- publishednode,
- pushop.remotephases.publicheads)
+ publishednode = [c.node() for c in pushop.outdatedphases]
+ publishedset = repo.revs('ancestors(%ln + %ln)',
+ publishednode,
+ pushop.remotephases.publicheads)
- rev = repo.unfiltered().changelog.nodemap.get
+ rev = repo.unfiltered().changelog.nodemap.get
- def remotebranchmap():
- # drop topic information from changeset about to be published
- result = collections.defaultdict(list)
- for branch, heads in origremotebranchmap().iteritems():
- if ':' not in branch:
- result[branch].extend(heads)
- else:
- namedbranch = branch.split(':', 1)[0]
- for h in heads:
- r = rev(h)
- if r is not None and r in publishedset:
- result[namedbranch].append(h)
- else:
- result[branch].append(h)
- for heads in result.itervalues():
- heads.sort()
- return result
+ def remotebranchmap():
+ # drop topic information from changeset about to be published
+ result = collections.defaultdict(list)
+ for branch, heads in origremotebranchmap().iteritems():
+ if ':' not in branch:
+ result[branch].extend(heads)
+ else:
+ namedbranch = branch.split(':', 1)[0]
+ for h in heads:
+ r = rev(h)
+ if r is not None and r in publishedset:
+ result[namedbranch].append(h)
+ else:
+ result[branch].append(h)
+ for heads in result.itervalues():
+ heads.sort()
+ return result
class repocls(repo.__class__):
# awful hack to see branch as "branch:topic"
--- a/hgext3rd/topic/flow.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/topic/flow.py Tue Jan 22 10:46:02 2019 -0500
@@ -7,7 +7,6 @@
extensions,
node,
phases,
- util,
)
from mercurial.i18n import _
@@ -75,9 +74,6 @@
def wrapphasediscovery(orig, pushop):
orig(pushop)
if getattr(pushop, 'publish', False):
- if not util.safehasattr(pushop, 'remotephases'):
- msg = _('--publish flag only supported from Mercurial 4.4 and higher')
- raise error.Abort(msg)
if not pushop.remotephases.publishing:
unfi = pushop.repo.unfiltered()
droots = pushop.remotephases.draftroots
@@ -87,8 +83,9 @@
def installpushflag(ui):
entry = extensions.wrapcommand(commands.table, 'push', wrappush)
- entry[1].append(('', 'publish', False,
- _('push the changeset as public')))
+ if not any(opt for opt in entry[1] if opt[1] == 'publish'): # hg <= 4.9
+ entry[1].append(('', 'publish', False,
+ _('push the changeset as public')))
extensions.wrapfunction(exchange.pushoperation, '__init__',
extendpushoperation)
extensions.wrapfunction(exchange, '_pushdiscoveryphase', wrapphasediscovery)
--- a/hgext3rd/topic/randomname.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/topic/randomname.py Tue Jan 22 10:46:02 2019 -0500
@@ -189,7 +189,6 @@
'pony',
'porcupine',
'porpoise',
- 'prairie',
'puffin',
'pug',
'quagga',
--- a/hgext3rd/topic/revset.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/topic/revset.py Tue Jan 22 10:46:02 2019 -0500
@@ -106,3 +106,52 @@
else:
branch = repo[None].branch()
return revset.baseset(stack.stack(repo, branch=branch, topic=topic)[1:]) & subset
+
+if util.safehasattr(revset, 'subscriptrelations'):
+ def stackrel(repo, subset, x, rel, n, order):
+ """This is a revset-flavored implementation of stack aliases.
+
+ The syntax is: rev#stack[n] or rev#s[n]. Plenty of logic is borrowed
+ from topic._namemap, but unlike that function, which prefers to abort
+ (e.g. when stack index is too high), this returns empty set to be more
+ revset-friendly.
+ """
+ s = revset.getset(repo, revset.fullreposet(repo), x)
+ if not s:
+ return revset.baseset()
+ revs = []
+ for r in s:
+ topic = repo[r].topic()
+ if topic:
+ st = stack.stack(repo, topic=topic)
+ else:
+ st = stack.stack(repo, branch=repo[r].branch())
+ if n < 0:
+ st = list(st)[1:]
+ else:
+ st = list(st)
+ try:
+ rev = st[n]
+ except IndexError:
+ continue
+ if rev == -1 and n == 0:
+ continue
+ if rev not in revs:
+ revs.append(rev)
+ return subset & revset.baseset(revs)
+
+ revset.subscriptrelations['stack'] = stackrel
+ revset.subscriptrelations['s'] = stackrel
+
+ def topicrel(repo, subset, x, rel, n, order):
+ ancestors = revset._ancestors
+ descendants = revset._descendants
+ subset = topicset(repo, subset, x)
+ if n <= 0:
+ n = -n
+ return ancestors(repo, subset, x, startdepth=n, stopdepth=n + 1)
+ else:
+ return descendants(repo, subset, x, startdepth=n, stopdepth=n + 1)
+
+ revset.subscriptrelations['topic'] = topicrel
+ revset.subscriptrelations['t'] = topicrel
--- a/hgext3rd/topic/stack.py Tue Jan 22 10:43:44 2019 -0500
+++ b/hgext3rd/topic/stack.py Tue Jan 22 10:46:02 2019 -0500
@@ -329,15 +329,32 @@
symbol = None
states = []
+ msg = ''
iscurrentrevision = repo.revs('%d and parents()', ctx.rev())
+ if opts.get('children'):
+ if branch:
+ t_msg = '-branch("%s")' % branch
+ if topic:
+ t_msg = '-topic("%s")' % topic
+ rev_msg = 'children(%s) and merge() %s'
+ revisions = repo.revs(rev_msg % (ctx.rev(), t_msg))
+ len_rev = len(revisions)
+ if len_rev > 0:
+ msg = 'external-children'
if iscurrentrevision:
- states.append('current')
symbol = '@'
+ if msg:
+ states.append('current - ' + msg)
+ else:
+ states.append('current')
if ctx.orphan():
symbol = '$'
- states.append('unstable')
+ if msg:
+ states.append('unstable - ' + msg)
+ else:
+ states.append('unstable')
if not isentry:
symbol = '^'
@@ -347,7 +364,10 @@
# none of the above if statments get executed
if not symbol:
symbol = ':'
- states.append('clean')
+ if msg:
+ states.append(msg)
+ else:
+ states.append('clean')
states.sort()
--- a/tests/test-amend.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-amend.t Tue Jan 22 10:46:02 2019 -0500
@@ -153,7 +153,7 @@
--close-branch mark a branch as closed, hiding it from the branch
list
-s --secret use the secret phase for committing
- -n --note VALUE store a note on amend
+ -n --note TEXT store a note on amend
-I --include PATTERN [+] include names matching the given patterns
-X --exclude PATTERN [+] exclude names matching the given patterns
-m --message TEXT use text as commit message
--- a/tests/test-discovery-obshashrange-cache.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-discovery-obshashrange-cache.t Tue Jan 22 10:46:02 2019 -0500
@@ -28,7 +28,7 @@
$ hg -R main debugbuilddag '.+7'
$ for node in `hg -R main log -T '{node}\n'`; do
- > echo -n $node | grep -o . | sort |tr -d "\n" > ancfile
+ > printf $node | grep -o . | sort |tr -d "\n" > ancfile
> anc=`cat ancfile`
> rm ancfile
> echo "marking $anc as predecessors of $node"
--- a/tests/test-discovery-obshashrange.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-discovery-obshashrange.t Tue Jan 22 10:46:02 2019 -0500
@@ -9,6 +9,10 @@
> blackbox =
> [defaults]
> blackbox = -l 100
+ > [blackbox]
+ > track = backupbundle, branchcache, cache, command, commandalias,
+ > commandfinish, debug, discovery, evoext-cache, evoext-obsdiscovery,
+ > incoming, tagscache
> [experimental]
> obshashrange=1
> verbose-obsolescence-exchange=1
@@ -190,9 +194,6 @@
remote: capabilities: _evoext_getbundle_obscommon _evoext_obshash_0 _evoext_obshash_1 _evoext_obshashrange_v1 batch * (glob)
remote: 1
sending protocaps command
- preparing listkeys for "phases"
- sending listkeys command
- received listkey for "phases": 58 bytes
query 1; heads
sending batch command
searching for changes
@@ -322,9 +323,6 @@
* @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> remote: capabilities: _evoext_getbundle_obscommon _evoext_obshash_0 _evoext_obshash_1 _evoext_obshashrange_v1 batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Aobsmarkers%3DV0%2CV1%0Aphases%3Dheads%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache%0Astream%3Dv2 changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (glob)
* @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> remote: 1 (glob)
* @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> sending protocaps command (glob)
- * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> preparing listkeys for "phases" (glob)
- * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> sending listkeys command (glob)
- * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> received listkey for "phases": 58 bytes (glob)
* @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> query 1; heads (glob)
* @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> sending batch command (glob)
* @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> taking quick initial sample (glob)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-issue5881.t Tue Jan 22 10:46:02 2019 -0500
@@ -0,0 +1,53 @@
+Test for issue 5881 present at https://bz.mercurial-scm.org/show_bug.cgi?id=5881
+===============================================================================
+which is about that if the working copy parent is obsolete then evolve update
+to its successor revision and stop; it doesn't continue to evolve remaining
+revisions those were suppossed to evovle.
+
+Setup
+=====
+
+ $ cat >> $HGRCPATH <<EOF
+ > [phases]
+ > publish = False
+ > [alias]
+ > glog = log -GT "{rev}:{node|short} {desc}\n ({bookmarks}) {phase}"
+ > [extensions]
+ > EOF
+ $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+
+ $ hg init issue5881
+ $ cd issue5881
+
+Prepare the directory by creating an orphan and update to its obsolete parent:
+
+ $ for ch in a b c; do echo $ch > $ch; hg ci -Am "added "$ch; done;
+ adding a
+ adding b
+ adding c
+ $ hg up 1 -q
+ $ hg ci --amend -m "updated b"
+ 1 new orphan changesets
+ $ hg up 1
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ working directory parent is obsolete! (5f6d8a4bf34a)
+ (use 'hg evolve' to update to its successor: e6048a693c0d)
+
+ $ hg glog
+ o 3:e6048a693c0d updated b
+ | () draft
+ | * 2:155349b645be added c
+ | | () draft
+ | @ 1:5f6d8a4bf34a added b
+ |/ () draft
+ o 0:9092f1db7931 added a
+ () draft
+
+Test `hg evolve` evolve all the revisions specified by user:
+ $ hg evolve -r .::
+ update:[3] updated b
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ working directory is now at e6048a693c0d
+ move:[2] added c
+ atop:[3] updated b
+ working directory is now at c3a628eb9aaf
--- a/tests/test-evolve-obshistory-complex.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve-obshistory-complex.t Tue Jan 22 10:46:02 2019 -0500
@@ -140,11 +140,11 @@
Then split
----------
- $ hg split "desc(fold0)" -d "0 0" << EOF
+ $ hg split --rev "desc(fold0)" -d "0 0" << EOF
> Y
> Y
> N
- > N
+ > Y
> Y
> Y
> EOF
@@ -164,7 +164,7 @@
examine changes to 'B'? [Ynesfdaq?] N
created new head
- Done splitting? [yN] N
+ continue splitting? [Ycdq?] Y
diff --git a/B b/B
new file mode 100644
examine changes to 'B'? [Ynesfdaq?] Y
@@ -174,11 +174,11 @@
record this change to 'B'? [Ynesfdaq?] Y
no more change to split
- $ hg split "desc(fold1)" -d "0 0" << EOF
+ $ hg split --rev "desc(fold1)" -d "0 0" << EOF
> Y
> Y
> N
- > N
+ > Y
> Y
> Y
> EOF
@@ -198,7 +198,7 @@
examine changes to 'D'? [Ynesfdaq?] N
created new head
- Done splitting? [yN] N
+ continue splitting? [Ycdq?] Y
diff --git a/D b/D
new file mode 100644
examine changes to 'D'? [Ynesfdaq?] Y
@@ -209,11 +209,11 @@
no more change to split
1 new orphan changesets
- $ hg split "desc(fold2)" -d "0 0" << EOF
+ $ hg split --rev "desc(fold2)" -d "0 0" << EOF
> Y
> Y
> N
- > N
+ > Y
> Y
> Y
> EOF
@@ -233,7 +233,7 @@
examine changes to 'F'? [Ynesfdaq?] N
created new head
- Done splitting? [yN] N
+ continue splitting? [Ycdq?] Y
diff --git a/F b/F
new file mode 100644
examine changes to 'F'? [Ynesfdaq?] Y
--- a/tests/test-evolve-obshistory-lots-of-splits.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve-obshistory-lots-of-splits.t Tue Jan 22 10:46:02 2019 -0500
@@ -43,16 +43,16 @@
> n
> n
> n
- > n
+ > y
> y
> y
> n
> n
- > n
+ > y
> y
> y
> n
- > n
+ > y
> y
> y
> EOF
@@ -82,7 +82,7 @@
examine changes to 'd'? [Ynesfdaq?] n
created new head
- Done splitting? [yN] n
+ continue splitting? [Ycdq?] y
diff --git a/b b/b
new file mode 100644
examine changes to 'b'? [Ynesfdaq?] y
@@ -99,7 +99,7 @@
new file mode 100644
examine changes to 'd'? [Ynesfdaq?] n
- Done splitting? [yN] n
+ continue splitting? [Ycdq?] y
diff --git a/c b/c
new file mode 100644
examine changes to 'c'? [Ynesfdaq?] y
@@ -112,7 +112,7 @@
new file mode 100644
examine changes to 'd'? [Ynesfdaq?] n
- Done splitting? [yN] n
+ continue splitting? [Ycdq?] y
diff --git a/d b/d
new file mode 100644
examine changes to 'd'? [Ynesfdaq?] y
--- a/tests/test-evolve-obshistory-split.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve-obshistory-split.t Tue Jan 22 10:46:02 2019 -0500
@@ -38,7 +38,7 @@
> y
> y
> n
- > n
+ > y
> y
> y
> EOF
@@ -58,7 +58,7 @@
examine changes to 'b'? [Ynesfdaq?] n
created new head
- Done splitting? [yN] n
+ continue splitting? [Ycdq?] y
diff --git a/b b/b
new file mode 100644
examine changes to 'b'? [Ynesfdaq?] y
--- a/tests/test-evolve-orphan-split.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve-orphan-split.t Tue Jan 22 10:46:02 2019 -0500
@@ -41,7 +41,7 @@
> y
> y
> n
- > y
+ > c
> EOF
0 files updated, 0 files merged, 3 files removed, 0 files unresolved
adding a
@@ -59,7 +59,7 @@
examine changes to 'b'? [Ynesfdaq?] n
created new head
- Done splitting? [yN] y
+ continue splitting? [Ycdq?] c
1 new orphan changesets
$ hg glog
@@ -121,7 +121,7 @@
> y
> y
> y
- > y
+ > c
> EOF
0 files updated, 0 files merged, 3 files removed, 0 files unresolved
adding a
@@ -152,7 +152,7 @@
record change 3/3 to 'c'? [Ynesfdaq?] y
created new head
- Done splitting? [yN] y
+ continue splitting? [Ycdq?] c
1 new orphan changesets
$ hg glog
--- a/tests/test-evolve-phase-divergence.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve-phase-divergence.t Tue Jan 22 10:46:02 2019 -0500
@@ -893,7 +893,7 @@
1 new phase-divergent changesets
$ hg glog -r f3794e5a91dc::
- @ 24:e450d05b7d27 added g
+ @ 24:390acb97e50a added f
| () draft
| o 23:428f7900a969 added g
| | () public
@@ -906,14 +906,14 @@
~
$ hg evolve --list
- e450d05b7d27: added g
+ 390acb97e50a: added f
phase-divergent: 21ae52e414e6 (immutable precursor)
phase-divergent: 428f7900a969 (immutable precursor)
Resolving phase divergence using `hg evolve`
$ hg evolve --phase-divergent --all
- recreate:[24] added g
+ recreate:[24] added f
atop:[23] added g
rebasing to destination parent: 21ae52e414e6
computing new diff
--- a/tests/test-evolve-stop-orphan.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve-stop-orphan.t Tue Jan 22 10:46:02 2019 -0500
@@ -109,9 +109,8 @@
Checking working dir
$ hg status
Checking for incomplete mergestate
- $ ls .hg/merge
- ls: cannot access .?\.hg/merge.?: No such file or directory (re)
- [2]
+ $ ls .hg/ | grep merge
+ [1]
Checking graph
$ hg glog
--- a/tests/test-evolve-templates.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve-templates.t Tue Jan 22 10:46:02 2019 -0500
@@ -272,7 +272,7 @@
> y
> y
> n
- > n
+ > y
> y
> y
> EOF
@@ -292,7 +292,7 @@
examine changes to 'b'? [Ynesfdaq?] n
created new head
- Done splitting? [yN] n
+ continue splitting? [Ycdq?] y
diff --git a/b b/b
new file mode 100644
examine changes to 'b'? [Ynesfdaq?] y
--- a/tests/test-evolve-topic.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve-topic.t Tue Jan 22 10:46:02 2019 -0500
@@ -257,7 +257,7 @@
$ hg topic -r 070c5573d8f9 bar
4 new orphan changesets
- changed topic on 1 changes
+ changed topic on 1 changesets to "bar"
$ hg up 16d6f664b17c
switching to topic bar
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -381,3 +381,63 @@
$ hg prev
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
[s3] add eee
+
+Check stackaliases(s#) works with --continue case also, while evolving:
+------------------------------------------------------------------------
+ $ hg up 18
+ switching to topic bar
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg evolve --all
+ move:[s2] add ggg
+ atop:[s1] add fff
+ move:[s3] add hhh
+ move:[s4] add iii
+ move:[s5] add jjj
+ working directory is now at 38a82cbb794a
+ $ hg up 18
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ $ echo "changes in hhh" > hhh
+ $ hg add hhh
+ $ hg ci --amend
+ 4 new orphan changesets
+ $ hg log -G
+ @ 26 - {bar} 2c295936ac04 add fff (draft)
+ |
+ | * 25 - {bar} 38a82cbb794a add jjj (draft)
+ | |
+ | * 24 - {bar} 4a44eba0fdb3 add iii (draft)
+ | |
+ | * 23 - {bar} 7acd9ea5d677 add hhh (draft)
+ | |
+ | * 22 - {bar} 735c7bd8f133 add ggg (draft)
+ | |
+ | x 18 - {bar} 793eb6370b2d add fff (draft)
+ |/
+ o 12 - {foo} 42b49017ff90 add eee (draft)
+ |
+ o 10 - {foo} d9cacd156ffc add ddd (draft)
+ |
+ o 2 - {foo} cced9bac76e3 add ccc (draft)
+ |
+ o 1 - {} a4dbed0837ea add bbb (draft)
+ |
+ o 0 - {} 199cc73e9a0b add aaa (draft)
+
+ $ hg evolve --all
+ move:[s2] add ggg
+ atop:[s1] add fff
+ move:[s3] add hhh
+ merging hhh
+ warning: conflicts while merging hhh! (edit, then use 'hg resolve --mark')
+ fix conflicts and see `hg help evolve.interrupted`
+ [1]
+ $ echo "resolved hhh" > hhh
+ $ hg resolve --mark hhh
+ (no more unresolved files)
+ continue: hg evolve --continue
+ $ hg evolve --continue
+ evolving 23:7acd9ea5d677 "add hhh"
+ move:[s4] add iii
+ atop:[s3] add hhh
+ move:[s5] add jjj
+ working directory is now at 119e4c126fb2
--- a/tests/test-evolve.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-evolve.t Tue Jan 22 10:46:02 2019 -0500
@@ -1523,3 +1523,110 @@
x 0:f7ad41964313 added a ()
+ $ cd ..
+
+Test which shows that orphanmerge evolution can result to crash because of
+lastsolved not being updated in case of orphanmerge:
+(It will be fixed in next patch)
+
+Prepare the repo:
+ $ hg init orphanmergerepo
+ $ cd orphanmergerepo
+ $ echo a > a
+ $ for fn in a b c; do echo foo > $fn; hg ci -Am "added "$fn; done;
+ adding a
+ adding b
+ adding c
+Lets create a merge commit so that we can create orhpan merge later:
+ $ hg up 1 -q
+ $ echo feature > f
+ $ hg ci -Am "added feature f"
+ adding f
+ created new head
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m "merge feature branch"
+ $ glog
+ @ 4:2c0a98d38026@default(draft) merge feature branch
+ |\
+ | o 3:4c33e511041e@default(draft) added feature f
+ | |
+ o | 2:8be98ac1a569@default(draft) added c
+ |/
+ o 1:80e6d2c47cfe@default(draft) added b
+ |
+ o 0:f7ad41964313@default(draft) added a
+
+
+Now make the parents of merge commit obsolete to get a orphan merge:
+ $ hg up 2 -q
+ $ echo "fixit" > c
+ $ hg ci --amend -m "updated c"
+ 1 new orphan changesets
+ $ hg up 3 -q
+ $ echo "fixit" > c
+ $ hg ci --amend -m "updated f"
+ $ glog
+ @ 6:086d9bedcd75@default(draft) updated f
+ |
+ | o 5:f84f2c548fbc@default(draft) updated c
+ |/
+ | * 4:2c0a98d38026@default(draft) merge feature branch
+ | |\
+ +---x 3:4c33e511041e@default(draft) added feature f
+ | |
+ | x 2:8be98ac1a569@default(draft) added c
+ |/
+ o 1:80e6d2c47cfe@default(draft) added b
+ |
+ o 0:f7ad41964313@default(draft) added a
+
+
+To check `lastsolved` contain right value after completion of orphan-merge
+resolution there should be one more trouble to be evolved; lets create one:
+ $ hg up 1 -q
+ $ echo d > d
+ $ hg ci -Am "added d"
+ adding c
+ adding d
+ created new head
+ $ echo e > e
+ $ hg ci -Am "added e"
+ adding e
+ $ hg up .^
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo "updated d" >> d
+ $ hg ci --amend -m "updated d"
+ 1 new orphan changesets
+ $ glog
+ @ 9:7c4d1834c346@default(draft) updated d
+ |
+ | * 8:421f7614462a@default(draft) added e
+ | |
+ | x 7:afe5acea1990@default(draft) added d
+ |/
+ | o 6:086d9bedcd75@default(draft) updated f
+ |/
+ | o 5:f84f2c548fbc@default(draft) updated c
+ |/
+ | * 4:2c0a98d38026@default(draft) merge feature branch
+ | |\
+ +---x 3:4c33e511041e@default(draft) added feature f
+ | |
+ | x 2:8be98ac1a569@default(draft) added c
+ |/
+ o 1:80e6d2c47cfe@default(draft) added b
+ |
+ o 0:f7ad41964313@default(draft) added a
+
+Now we have one orphan merge and one more orphan cset that we just created.
+Lets evolve:
+ $ hg evolve --all --any
+ move:[4] merge feature branch
+ atop:[5] updated c
+ move:[10] merge feature branch
+ atop:[6] updated f
+ move:[8] added e
+ atop:[9] updated d
+ working directory is now at 7c67cee06242
--- a/tests/test-fold.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-fold.t Tue Jan 22 10:46:02 2019 -0500
@@ -244,5 +244,29 @@
|
o 0 - 1ea73414a91b r0 [debugbuilddag] (public)
+Test order of proposed commit message
+
+ $ hg fold --exact --hidden -r 4 -r 5 -r 6
+ 2 new content-divergent changesets
+ 3 changesets folded
+ $ hg log -r tip -T '{desc}'
+ r4
+
+
+ r5
+
+
+ r6 (no-eol)
+ $ hg fold --exact --hidden -r 6 -r 4 -r 5
+ 3 changesets folded
+ $ hg log -r tip -T '{desc}'
+ r4
+
+
+ r5
+
+
+ r6 (no-eol)
+
$ cd ..
--- a/tests/test-grab.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-grab.t Tue Jan 22 10:46:02 2019 -0500
@@ -24,9 +24,9 @@
options:
- -r --rev VALUE revision to pick
- -c --continue continue interrupted pick
- -a --abort abort interrupted pick
+ -r --rev REV revision to pick
+ -c --continue continue interrupted pick
+ -a --abort abort interrupted pick
(some details hidden, use --verbose to show complete help)
--- a/tests/test-obsolete-push.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-obsolete-push.t Tue Jan 22 10:46:02 2019 -0500
@@ -4,6 +4,7 @@
> [extensions]
> EOF
$ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+ $ echo "topic=$(echo $(dirname $TESTDIR))/hgext3rd/topic/" >> $HGRCPATH
$ template='{rev}:{node|short}@{branch}({separate("/", obsolete, phase)}) {desc|firstline}\n'
$ glog() {
@@ -72,12 +73,12 @@
$ hg push -r .
pushing to $TESTTMP/source
abort: push would publish 1 changesets
- (behavior controlled by 'experimental.auto-publish' config)
+ (* 'experimental.auto-publish' config) (glob)
[255]
$ hg push
pushing to $TESTTMP/source
abort: push would publish 1 changesets
- (behavior controlled by 'experimental.auto-publish' config)
+ (* 'experimental.auto-publish' config) (glob)
[255]
warning behavior
@@ -91,3 +92,15 @@
adding manifests
adding file changes
added 0 changesets with 0 changes to 1 files
+
+--publish overrides auto-publish
+
+ $ echo d > d
+ $ hg ci -qAm D d
+ $ hg push -r . --publish --config experimental.auto-publish=abort
+ pushing to $TESTTMP/source
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
--- a/tests/test-prev-next.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-prev-next.t Tue Jan 22 10:46:02 2019 -0500
@@ -184,7 +184,7 @@
$ hg amend -m 'added b (2)'
1 new orphan changesets
- $ hg next
+ $ hg next --no-evolve
no children
(1 unstable changesets to be evolved here, do you want --evolve?)
[1]
@@ -231,7 +231,7 @@
$ hg am -m 'added b (3)'
2 new orphan changesets
- $ hg next
+ $ hg next --no-evolve
no children
(2 unstable changesets to be evolved here, do you want --evolve?)
[1]
@@ -375,6 +375,7 @@
$ hg next --evolve
abort: uncommitted changes
+ (use `hg amend`, `hg revert` or `hg shelve`)
[255]
$ cd ..
@@ -482,3 +483,107 @@
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
use 'hg resolve' to retry unresolved file merges
[2] added bar
+
+Add test which shows that now `next` command does not get confused by split:
+----------------------------------------------------------------------------
+ $ cd ..
+ $ mkdir nextconfused
+ $ cd nextconfused
+ $ hg init
+ $ echo firstline > a
+ $ hg add a
+ $ hg ci -qm A
+ $ echo bbbbb > b
+ $ echo secondline >> a
+ $ hg add b
+ $ hg ci -qm B
+ $ echo ccccc > c
+ $ hg add c
+ $ hg ci -qm C
+ $ hg log -GT "{rev}:{node|short} {desc}\n"
+ @ 2:fdc998261dcb C
+ |
+ o 1:cc0edb0cc2b1 B
+ |
+ o 0:cae96ff49c84 A
+
+ $ hg up 1
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg split << EOF
+ > y
+ > y
+ > n
+ > Y
+ > y
+ > y
+ > EOF
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ reverting a
+ adding b
+ diff --git a/a b/a
+ 1 hunks, 1 lines changed
+ examine changes to 'a'? [Ynesfdaq?] y
+
+ @@ -1,1 +1,2 @@
+ firstline
+ +secondline
+ record change 1/2 to 'a'? [Ynesfdaq?] y
+
+ diff --git a/b b/b
+ new file mode 100644
+ examine changes to 'b'? [Ynesfdaq?] n
+
+ created new head
+ continue splitting? [Ycdq?] Y
+ diff --git a/b b/b
+ new file mode 100644
+ examine changes to 'b'? [Ynesfdaq?] y
+
+ @@ -0,0 +1,1 @@
+ +bbbbb
+ record this change to 'b'? [Ynesfdaq?] y
+
+ no more change to split
+ 1 new orphan changesets
+
+ $ hg up 3 -q
+ $ hg log -GT "{rev}:{node|short} {desc}\n"
+ o 4:279f6cab32b5 B
+ |
+ |
+ | new desc
+ @ 3:a9f74d07e45c B
+ |
+ |
+ | new desc
+ | * 2:fdc998261dcb C
+ | |
+ | x 1:cc0edb0cc2b1 B
+ |/
+ o 0:cae96ff49c84 A
+
+ $ hg ci --amend -m "B modified"
+ 1 new orphan changesets
+ $ hg log -GT "{rev}:{node|short} {desc}\n"
+ @ 5:64ab03d3110c B modified
+ |
+ | * 4:279f6cab32b5 B
+ | |
+ | |
+ | | new desc
+ | x 3:a9f74d07e45c B
+ |/
+ |
+ | new desc
+ | * 2:fdc998261dcb C
+ | |
+ | x 1:cc0edb0cc2b1 B
+ |/
+ o 0:cae96ff49c84 A
+
+ $ hg next --evolve << EOF
+ > q
+ > EOF
+ move:[4] B
+ atop:[5] B modified
+ working directory now at 1b434459c7e7
--- a/tests/test-rewind.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-rewind.t Tue Jan 22 10:46:02 2019 -0500
@@ -460,7 +460,7 @@
> y
> f
> d
- > y
+ > c
> EOF
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
adding C
@@ -478,7 +478,7 @@
examine changes to 'D'? [Ynesfdaq?] d
created new head
- Done splitting? [yN] y
+ continue splitting? [Ycdq?] c
$ hg log -G
@ changeset: 5:9576e80d6851
| tag: tip
--- a/tests/test-split.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-split.t Tue Jan 22 10:46:02 2019 -0500
@@ -4,6 +4,8 @@
$ . $TESTDIR/testlib/common.sh
$ cat >> $HGRCPATH <<EOF
+ > [alias]
+ > glog = log -G -T "{rev}:{node|short} {desc|firstline} ({phase})\n"
> [defaults]
> amend=-d "0 0"
> fold=-d "0 0"
@@ -55,7 +57,7 @@
> y
> y
> n
- > N
+ > Y
> y
> y
> EOF
@@ -79,7 +81,7 @@
record change 2/2 to '_d'? [Ynesfdaq?] n
created new head
- Done splitting? [yN] N
+ continue splitting? [Ycdq?] Y
diff --git a/_d b/_d
new file mode 100644
examine changes to '_d'? [Ynesfdaq?] y
@@ -179,7 +181,7 @@
> y
> y
> n
- > y
+ > c
> EOF
2 files updated, 0 files merged, 2 files removed, 0 files unresolved
reverting _b
@@ -201,7 +203,7 @@
record change 2/2 to '_c'? [Ynesfdaq?] n
created new head
- Done splitting? [yN] y
+ continue splitting? [Ycdq?] c
2 new orphan changesets
Stop before splitting the commit completely creates a commit with all the
@@ -281,7 +283,7 @@
> y
> y
> n
- > y
+ > c
> EOF
(leaving bookmark bookB)
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -302,7 +304,7 @@
examine changes to '_d'? [Ynesfdaq?] n
created new head
- Done splitting? [yN] y
+ continue splitting? [Ycdq?] c
$ hg log -G -r "3f134f739075::"
@ changeset: 16:452a26648478
| bookmark: bookA
@@ -366,7 +368,7 @@
[255]
Running split with tip revision, specified as unnamed argument
- $ hg split . << EOF
+ $ hg split --rev . << EOF
> q
> EOF
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -379,11 +381,10 @@
[255]
Running split with both unnamed and named revision arguments shows an error msg
- $ hg split . --rev .^ << EOF
+ $ hg split --rev . --rev .^ << EOF
> q
> EOF
abort: more than one revset is given
- (use either `hg split <rs>` or `hg split --rev <rs>`, not both)
[255]
Split empty commit (issue5191)
@@ -435,7 +436,7 @@
> Y
> Y
> N
- > Y
+ > c
> Y
> Y
> EOF
@@ -454,16 +455,7 @@
new file mode 100644
examine changes to 'celeste'? [Ynesfdaq?] N
- Done splitting? [yN] Y
- diff --git a/celeste b/celeste
- new file mode 100644
- examine changes to 'celeste'? [Ynesfdaq?] Y
-
- @@ -0,0 +1,1 @@
- +celeste
- record this change to 'celeste'? [Ynesfdaq?] Y
-
- no more change to split
+ continue splitting? [Ycdq?] c
Check that the topic is still here
@@ -537,7 +529,7 @@
$ hg split -r . << EOF
> Y
> N
- > N
+ > Y
> Y
> EOF
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
@@ -551,7 +543,7 @@
new file mode 100644
examine changes to 'SPLIT2'? [Ynesfdaq?] N
- Done splitting? [yN] N
+ continue splitting? [Ycdq?] Y
diff --git a/SPLIT2 b/SPLIT2
new file mode 100644
examine changes to 'SPLIT2'? [Ynesfdaq?] Y
@@ -651,3 +643,479 @@
date: Thu Jan 01 00:00:00 1970 +0000
summary: split10
+
+Check prompt options
+--------------------
+
+Look at the help (both record and split helps)
+
+ $ hg split -r tip << EOF
+ > Y
+ > ?
+ > d
+ > ?
+ > q
+ > EOF
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ adding SPLIT3
+ adding SPLIT4
+ diff --git a/SPLIT3 b/SPLIT3
+ new file mode 100644
+ examine changes to 'SPLIT3'? [Ynesfdaq?] Y
+
+ diff --git a/SPLIT4 b/SPLIT4
+ new file mode 100644
+ examine changes to 'SPLIT4'? [Ynesfdaq?] ?
+
+ y - yes, record this change
+ n - no, skip this change
+ e - edit this change manually
+ s - skip remaining changes to this file
+ f - record remaining changes to this file
+ d - done, skip remaining changes and files
+ a - record all changes to all remaining files
+ q - quit, recording no changes
+ ? - ? (display help)
+ examine changes to 'SPLIT4'? [Ynesfdaq?] d
+
+ continue splitting? [Ycdq?] ?
+ y - yes, continue selection
+ c - commit, select all remaining changes
+ d - discard, discard remaining changes
+ q - quit, abort the split
+ ? - ?, display help
+ continue splitting? [Ycdq?] q
+ transaction abort!
+ rollback completed
+ abort: user quit
+ [255]
+
+discard some of changeset during split
+
+ $ cat >> $HGRCPATH <<EOF
+ > [experimental]
+ > evolution=all
+ > evolutioncommands=
+ > EOF
+
+ $ hg export
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Branch another-branch
+ # Node ID 56a59faa8af70dc104faa905231731ffece5f18a
+ # Parent 75695e3e2300d316cc515c4c25bab8b825ef1433
+ # EXP-Topic mytopic
+ split10
+
+ diff --git a/SPLIT2 b/SPLIT2
+ new file mode 100644
+ $ hg add SPLIT3
+ $ hg amend
+ 1 new orphan changesets
+ $ hg export
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Branch another-branch
+ # Node ID 3acb634dc68ddb4dea75a9cee982955bc1f3e8cd
+ # Parent 75695e3e2300d316cc515c4c25bab8b825ef1433
+ # EXP-Topic mytopic
+ split10
+
+ diff --git a/SPLIT2 b/SPLIT2
+ new file mode 100644
+ diff --git a/SPLIT3 b/SPLIT3
+ new file mode 100644
+ $ hg split << EOF
+ > Y
+ > d
+ > d
+ > EOF
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ diff --git a/SPLIT2 b/SPLIT2
+ new file mode 100644
+ examine changes to 'SPLIT2'? [Ynesfdaq?] Y
+
+ diff --git a/SPLIT3 b/SPLIT3
+ new file mode 100644
+ examine changes to 'SPLIT3'? [Ynesfdaq?] d
+
+ continue splitting? [Ycdq?] d
+ discarding remaining changes
+ forgetting SPLIT3
+ $ hg export
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Branch another-branch
+ # Node ID db690d5566962489d65945c90b468b44e0b1507a
+ # Parent 75695e3e2300d316cc515c4c25bab8b825ef1433
+ # EXP-Topic mytopic
+ split12
+
+ diff --git a/SPLIT2 b/SPLIT2
+ new file mode 100644
+ $ hg status
+ ? SPLIT3
+ ? SPLIT4
+ ? editor.sh
+ ? num
+
+Test restricting the split to a subset of files
+-----------------------------------------------
+
+ $ hg add SPLIT3 SPLIT4
+ $ hg amend
+
+Only run on 2 files
+
+(remaining changes gathered with unmatched one)
+
+ $ hg split SPLIT2 SPLIT3 << EOF
+ > y
+ > n
+ > c
+ > EOF
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ diff --git a/SPLIT2 b/SPLIT2
+ new file mode 100644
+ examine changes to 'SPLIT2'? [Ynesfdaq?] y
+
+ diff --git a/SPLIT3 b/SPLIT3
+ new file mode 100644
+ examine changes to 'SPLIT3'? [Ynesfdaq?] n
+
+ continue splitting? [Ycdq?] c
+ $ hg status --change '.~1'
+ A SPLIT2
+ $ hg status --change '.'
+ A SPLIT3
+ A SPLIT4
+ $ hg fold --from '.~1'
+ 2 changesets folded
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+(no remaining changes)
+
+ $ hg split SPLIT2 SPLIT3 << EOF
+ > y
+ > n
+ > y
+ > y
+ > EOF
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ diff --git a/SPLIT2 b/SPLIT2
+ new file mode 100644
+ examine changes to 'SPLIT2'? [Ynesfdaq?] y
+
+ diff --git a/SPLIT3 b/SPLIT3
+ new file mode 100644
+ examine changes to 'SPLIT3'? [Ynesfdaq?] n
+
+ continue splitting? [Ycdq?] y
+ diff --git a/SPLIT3 b/SPLIT3
+ new file mode 100644
+ examine changes to 'SPLIT3'? [Ynesfdaq?] y
+
+ no more change to split
+ $ hg status --change '.~2'
+ A SPLIT2
+ $ hg status --change '.~1'
+ A SPLIT3
+ $ hg status --change '.'
+ A SPLIT4
+ $ hg fold --from '.~2'
+ 3 changesets folded
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+(only all matched selected)
+
+ $ hg split SPLIT2 SPLIT3 << EOF
+ > y
+ > y
+ > EOF
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ diff --git a/SPLIT2 b/SPLIT2
+ new file mode 100644
+ examine changes to 'SPLIT2'? [Ynesfdaq?] y
+
+ diff --git a/SPLIT3 b/SPLIT3
+ new file mode 100644
+ examine changes to 'SPLIT3'? [Ynesfdaq?] y
+
+ no more change to split
+ $ hg status --change '.~1'
+ A SPLIT2
+ A SPLIT3
+ $ hg status --change '.'
+ A SPLIT4
+ $ hg fold --from '.~1'
+ 2 changesets folded
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Check that discard does not alter unmatched files
+
+ $ hg split SPLIT2 SPLIT3 << EOF
+ > y
+ > n
+ > d
+ > EOF
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ diff --git a/SPLIT2 b/SPLIT2
+ new file mode 100644
+ examine changes to 'SPLIT2'? [Ynesfdaq?] y
+
+ diff --git a/SPLIT3 b/SPLIT3
+ new file mode 100644
+ examine changes to 'SPLIT3'? [Ynesfdaq?] n
+
+ continue splitting? [Ycdq?] d
+ discarding remaining changes
+ no more change to split
+ $ hg status --change '.~1'
+ A SPLIT2
+ $ hg status --change '.'
+ A SPLIT4
+ $ hg fold --from '.~1'
+ 2 changesets folded
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg add SPLIT3
+ $ hg amend
+
+Non interractive run
+--------------------
+
+No patterns
+
+ $ hg split --no-interactive
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ abort: no files of directories specified
+ (do you want --interactive)
+ [255]
+
+Selecting unrelated file
+(should we abort?)
+
+ $ hg split --no-interactive SPLIT1
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ no more change to split
+ $ hg status --change '.'
+ A SPLIT2
+ A SPLIT3
+ A SPLIT4
+
+Selecting one file
+
+ $ hg split --no-interactive SPLIT2
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ no more change to split
+ $ hg status --change '.~1'
+ A SPLIT2
+ $ hg status --change '.'
+ A SPLIT3
+ A SPLIT4
+ $ hg fold --from '.~1'
+ 2 changesets folded
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Selecting two files
+
+ $ hg split --no-interactive SPLIT2 SPLIT3
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ no more change to split
+ $ hg status --change '.~1'
+ A SPLIT2
+ A SPLIT3
+ $ hg status --change '.'
+ A SPLIT4
+ $ hg fold --from '.~1'
+ 2 changesets folded
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Selecting all files
+(should we abort?)
+
+ $ hg split --no-interactive .
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding SPLIT2
+ adding SPLIT3
+ adding SPLIT4
+ no more change to split
+ $ hg status --change '.'
+ A SPLIT2
+ A SPLIT3
+ A SPLIT4
+
+ $ cd ..
+
+Testing that `hg evolve` choose right destination after split && prune (issue5686)
+--------------------------------------------------------------------------------
+
+Prepare the repository:
+ $ hg init issue5686
+ $ cd issue5686
+ $ echo p > p
+ $ hg ci -Amp
+ adding p
+
+ $ for ch in a b; do echo $ch > $ch; done;
+ $ hg ci -Am "added a and b"
+ adding a
+ adding b
+ $ echo c > c
+ $ hg ci -Amc
+ adding c
+ $ hg glog
+ @ 2:ab6ca3ebca74 c (draft)
+ |
+ o 1:79f47e067e66 added a and b (draft)
+ |
+ o 0:a5a1faba8d26 p (draft)
+
+
+To create commits with the number of split
+ $ echo 0 > num
+ $ cat > editor.sh << '__EOF__'
+ > NUM=$(cat num)
+ > NUM=`expr "$NUM" + 1`
+ > echo "$NUM" > num
+ > echo "split$NUM" > "$1"
+ > __EOF__
+ $ export HGEDITOR="\"sh\" \"editor.sh\""
+
+Splitting the revision 1 to SPLIT1 and SPLIT2 which contains file a and b resp:
+ $ hg split -r 1 <<EOF
+ > y
+ > y
+ > n
+ > y
+ > y
+ > y
+ > EOF
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ adding a
+ adding b
+ diff --git a/a b/a
+ new file mode 100644
+ examine changes to 'a'? [Ynesfdaq?] y
+
+ @@ -0,0 +1,1 @@
+ +a
+ record change 1/2 to 'a'? [Ynesfdaq?] y
+
+ diff --git a/b b/b
+ new file mode 100644
+ examine changes to 'b'? [Ynesfdaq?] n
+
+ created new head
+ (consider using topic for lightweight branches. See 'hg help topic')
+ continue splitting? [Ycdq?] y
+ diff --git a/b b/b
+ new file mode 100644
+ examine changes to 'b'? [Ynesfdaq?] y
+
+ @@ -0,0 +1,1 @@
+ +b
+ record this change to 'b'? [Ynesfdaq?] y
+
+ no more change to split
+ 1 new orphan changesets
+
+ $ hg glog -p
+ @ 4:5cf253fa63fa split2 (draft)
+ | diff --git a/b b/b
+ | new file mode 100644
+ | --- /dev/null
+ | +++ b/b
+ | @@ -0,0 +1,1 @@
+ | +b
+ |
+ o 3:88437e073cd4 split1 (draft)
+ | diff --git a/a b/a
+ | new file mode 100644
+ | --- /dev/null
+ | +++ b/a
+ | @@ -0,0 +1,1 @@
+ | +a
+ |
+ | * 2:ab6ca3ebca74 c (draft)
+ | | diff --git a/c b/c
+ | | new file mode 100644
+ | | --- /dev/null
+ | | +++ b/c
+ | | @@ -0,0 +1,1 @@
+ | | +c
+ | |
+ | x 1:79f47e067e66 added a and b (draft)
+ |/ diff --git a/a b/a
+ | new file mode 100644
+ | --- /dev/null
+ | +++ b/a
+ | @@ -0,0 +1,1 @@
+ | +a
+ | diff --git a/b b/b
+ | new file mode 100644
+ | --- /dev/null
+ | +++ b/b
+ | @@ -0,0 +1,1 @@
+ | +b
+ |
+ o 0:a5a1faba8d26 p (draft)
+ diff --git a/p b/p
+ new file mode 100644
+ --- /dev/null
+ +++ b/p
+ @@ -0,0 +1,1 @@
+ +p
+
+Now if we prune revision 4 the expected destination of orphan cset 2 is 3. Lets
+check evolve does as expected:
+
+The fix is 4.9 only, so we simply cheat on older version
+
+Pruning revision 4 (current one):
+ $ hg prune .
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ working directory now at 88437e073cd4
+ 1 changesets pruned
+ $ hg rebase -r 2 -d 3 --config extensions.rebase=
+ rebasing 2:ab6ca3ebca74 "c"
+ $ hg up
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg glog
+ @ 5:21a63bd6ee88 c (draft)
+ |
+ o 3:88437e073cd4 split1 (draft)
+ |
+ o 0:a5a1faba8d26 p (draft)
+
--- a/tests/test-stack-branch.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-stack-branch.t Tue Jan 22 10:46:02 2019 -0500
@@ -309,7 +309,7 @@
----------------------------------------------------
$ hg topic --rev b4::b5 sometopic
- changed topic on 2 changes
+ changed topic on 2 changesets to "sometopic"
$ hg stack
### target: foo (branch)
s3$ c_f (unstable)
--- a/tests/test-topic-change.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-topic-change.t Tue Jan 22 10:46:02 2019 -0500
@@ -51,7 +51,7 @@
Clearing topic from revision without topic
$ hg topic -r . --clear
- changed topic on 0 changes
+ cleared topic on 0 changesets
Clearing current topic when no active topic is not error
@@ -62,7 +62,7 @@
$ hg topic -r 0:: foo
switching to topic foo
- changed topic on 8 changes
+ changed topic on 8 changesets to "foo"
$ hg glog
@ 15:05095f607171 {foo}
| Added h ()
@@ -100,7 +100,7 @@
$ hg topic -r abcedffeae90:: bar
switching to topic bar
- changed topic on 4 changes
+ changed topic on 4 changesets to "bar"
$ hg glog
@ 19:d7d36e193ea7 {bar}
| Added h ()
@@ -139,7 +139,7 @@
$ hg topic -r . --current
active topic 'foobar' grew its first changeset
(see 'hg help topics' for more information)
- changed topic on 1 changes
+ changed topic on 1 changesets to "foobar"
$ hg glog -r .
@ 20:c2d6b7df5dcf {foobar}
| Added h ()
@@ -149,7 +149,7 @@
$ hg topic -r 9::10 --current
5 new orphan changesets
- changed topic on 2 changes
+ changed topic on 2 changesets to "foobar"
$ hg glog
o 22:1b88140feefe {foobar}
| Added c ()
@@ -302,7 +302,7 @@
$ hg topic -r . --clear
clearing empty topic "watwat"
active topic 'watwat' is now empty
- changed topic on 1 changes
+ cleared topic on 1 changesets
$ hg glog
@ 31:c48d6d71b2d9 {}
@@ -335,7 +335,7 @@
$ hg bookmark bookboo
$ hg topic -r . movebook
switching to topic movebook
- changed topic on 1 changes
+ changed topic on 1 changesets to "movebook"
$ hg glog
@ 32:1b83d11095b9 {movebook}
| Added h (book bookboo)
@@ -376,7 +376,7 @@
$ hg topic -r . watwat
switching to topic watwat
1 new orphan changesets
- changed topic on 1 changes
+ changed topic on 1 changesets to "watwat"
$ hg glog
@ 33:894983f69e69 {watwat}
--- a/tests/test-topic-stack-complex.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-topic-stack-complex.t Tue Jan 22 10:46:02 2019 -0500
@@ -63,7 +63,7 @@
> y
> y
> n
- > y
+ > c
> EOF
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
adding c
@@ -80,7 +80,7 @@
new file mode 100644
examine changes to 'd'? [Ynesfdaq?] n
- Done splitting? [yN] y
+ continue splitting? [Ycdq?] c
1 new orphan changesets
$ hg stack
--- a/tests/test-topic-stack.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-topic-stack.t Tue Jan 22 10:46:02 2019 -0500
@@ -229,8 +229,52 @@
s1: c_c
s0^ c_b (base)
+merge case (displaying info about external)
+-------------------------------------------
+
+ $ hg up default
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ $ hg topics zzz
+ marked working directory as topic: zzz
+ $ echo zzz > zzz
+ $ hg add zzz
+ $ hg commit -m zzz_a
+ active topic 'zzz' grew its first changeset
+ (see 'hg help topics' for more information)
+ $ hg merge foo
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg commit -m "merged foo"
+
+stack -m display data about child
+
+ $ hg stack foo
+ ### topic: foo
+ ### target: default (branch)
+ s4: c_f
+ s3: c_e
+ s2: c_d
+ s1: c_c
+ s0^ c_b (base)
+
+ $ hg stack foo --children
+ ### topic: foo
+ ### target: default (branch)
+ s4: c_f (external-children)
+ s3: c_e
+ s2: c_d
+ s1: c_c
+ s0^ c_b (base)
+
error case, nothing to list
+ $ hg strip --config extensions.strip= t1 --no-backup
+ 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
+
+ $ hg up foo
+ switching to topic foo
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
$ hg topic --clear
$ hg stack
### target: default (branch)
@@ -495,7 +539,7 @@
$ hg topic foobar -r 'desc(c_e) + desc(c_D)'
switching to topic foobar
4 new orphan changesets
- changed topic on 2 changes
+ changed topic on 2 changesets to "foobar"
$ hg log -G
@ 17 default {foobar} draft c_D
|
@@ -850,7 +894,7 @@
> y
> y
> n
- > y
+ > c
> EOF
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
adding Z
@@ -867,7 +911,7 @@
new file mode 100644
examine changes to 'ggg'? [Ynesfdaq?] n
- Done splitting? [yN] y
+ continue splitting? [Ycdq?] c
$ hg --config extensions.evolve= obslog --all
o dde94df880e9 (21) c_G
--- a/tests/test-topic-tutorial.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-topic-tutorial.t Tue Jan 22 10:46:02 2019 -0500
@@ -1368,8 +1368,8 @@
to do that rebase by hand.:
$ hg next --evolve
- move:[14] Adding saw
- atop:[18] Adding hammer to the shopping list
+ move:[s2] Adding saw
+ atop:[s1] Adding hammer to the shopping list
working directory now at d5c51ee5762a
$ hg stack
@@ -1383,8 +1383,8 @@
One more to go:
$ hg next --evolve
- move:[15] Adding drill
- atop:[19] Adding saw
+ move:[s3] Adding drill
+ atop:[s2] Adding saw
working directory now at bae3758e46bf
$ hg stack
--- a/tests/test-topic.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-topic.t Tue Jan 22 10:46:02 2019 -0500
@@ -819,7 +819,40 @@
s0^ Add file delta (base current)
$ hg topics --age
- * fran (1970-01-01 by test)
+ * fran (1970-01-01 by test, 1 changesets)
+
+ $ cd ..
+
+Relation subscript in revsets
+=============================
+
+ $ hg init more-than-one-commit-per-topic
+ $ cd more-than-one-commit-per-topic
+ $ cat > .hg/hgrc << EOF
+ > [phases]
+ > publish=false
+ > EOF
+
+ $ echo 0 > foo
+ $ hg ci -qAm 0
+ $ hg topic featureA
+ marked working directory as topic: featureA
+ $ echo 1 > foo
+ $ hg ci -qm 1
+ $ echo 2 > foo
+ $ hg ci -qm 2
+ $ echo 3 > foo
+ $ hg ci -qm 3
+ $ hg topic --clear
+ $ echo 4 > foo
+ $ hg ci -qm 4
+
+ $ tlog 'all()'
+ 0:
+ 1: featureA
+ 2: featureA
+ 3: featureA
+ 4:
$ cd ..
@@ -863,7 +896,7 @@
$ hg topic topic1970 --rev 0
switching to topic topic1970
- changed topic on 1 changes
+ changed topic on 1 changesets to "topic1970"
$ hg add b
$ hg topic topic1990
@@ -903,18 +936,23 @@
* topic2010 (1 changesets)
$ hg topics --age
- * topic2010 (2010-01-01 by bar)
- topic1990 (1990-01-01 by foo)
- topic1970 (1970-01-01 by test)
+ * topic2010 (2010-01-01 by bar, 1 changesets)
+ topic1990 (1990-01-01 by foo, 1 changesets)
+ topic1970 (1970-01-01 by test, 1 changesets)
+
+ $ hg topics --age --verbose
+ * topic2010 (2010-01-01 by bar, on branch: default, 1 changesets)
+ topic1990 (1990-01-01 by foo, on branch: default, 1 changesets)
+ topic1970 (1970-01-01 by test, on branch: default, 1 changesets)
$ hg up topic1970
switching to topic topic1970
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ hg topics --age
- topic2010 (2010-01-01 by bar)
- topic1990 (1990-01-01 by foo)
- * topic1970 (1970-01-01 by test)
+ topic2010 (2010-01-01 by bar, 1 changesets)
+ topic1990 (1990-01-01 by foo, 1 changesets)
+ * topic1970 (1970-01-01 by test, 1 changesets)
$ hg topics --age random
abort: cannot use --age while setting a topic
--- a/tests/test-tutorial.t Tue Jan 22 10:43:44 2019 -0500
+++ b/tests/test-tutorial.t Tue Jan 22 10:46:02 2019 -0500
@@ -934,9 +934,9 @@
options ([+] can be repeated):
-a --all uncommit all changes when no arguments given
- -r --rev VALUE revert commit content to REV instead
+ -r --rev REV revert commit content to REV instead
--revert discard working directory changes after uncommit
- -n --note VALUE store a note on uncommit
+ -n --note TEXT store a note on uncommit
-I --include PATTERN [+] include names matching the given patterns
-X --exclude PATTERN [+] exclude names matching the given patterns
-m --message TEXT use text as commit message
@@ -973,16 +973,16 @@
options ([+] can be repeated):
- -r --rev VALUE [+] revision to fold
- --exact only fold specified revisions
- --from fold revisions linearly to working copy parent
- -n --note VALUE store a note on fold
- -m --message TEXT use text as commit message
- -l --logfile FILE read commit message from file
- -d --date DATE record the specified date as commit date
- -u --user USER record the specified user as committer
- -D --current-date record the current date as commit date
- -U --current-user record the current user as committer
+ -r --rev REV [+] revision to fold
+ --exact only fold specified revisions
+ --from fold revisions linearly to working copy parent
+ -n --note TEXT store a note on fold
+ -m --message TEXT use text as commit message
+ -l --logfile FILE read commit message from file
+ -d --date DATE record the specified date as commit date
+ -u --user USER record the specified user as committer
+ -D --current-date record the current date as commit date
+ -U --current-user record the current user as committer
(some details hidden, use --verbose to show complete help)