--- a/CHANGELOG Mon Feb 11 21:33:02 2019 +0800
+++ b/CHANGELOG Wed Feb 13 19:18:17 2019 +0800
@@ -1,6 +1,13 @@
Changelog
=========
+8.4.0 - in progress
+-------------------
+
+ * evolve: improved support for content-divergence with public changesets
+ * stack: support ranges in revsets indexing
+ * pick: add the standard `--tool` option
+
8.4.0 -- 2019-12-22
-------------------
--- a/hgext3rd/evolve/cmdrewrite.py Mon Feb 11 21:33:02 2019 +0800
+++ b/hgext3rd/evolve/cmdrewrite.py Wed Feb 13 19:18:17 2019 +0800
@@ -159,7 +159,6 @@
old = repo['.']
p1 = old.p1()
rewriteutil.precheck(repo, [old.rev()], 'amend')
- bookmarkupdater = rewriteutil.bookmarksupdater(repo, old.node(), tr)
diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
diffopts.nodates = True
diffopts.git = True
@@ -176,11 +175,11 @@
metadata = {}
if opts.get('note'):
metadata['note'] = opts['note']
- obsolete.createmarkers(repo, [(old, (repo[newnode],))],
- metadata=metadata, operation='amend')
+ replacements = {old.node(): [newnode]}
+ scmutil.cleanupnodes(repo, replacements, operation='amend',
+ metadata=metadata)
phases.retractboundary(repo, tr, old.phase(), [newnode])
hg.updaterepo(repo, newnode, True)
- bookmarkupdater(newnode)
tr.close()
finally:
if tr is not None:
@@ -523,7 +522,6 @@
# Recommit the filtered changeset
tr = repo.transaction('uncommit')
- updatebookmarks = rewriteutil.bookmarksupdater(repo, old.node(), tr)
if interactive:
opts['all'] = True
match = scmutil.match(old, pats, opts)
@@ -548,8 +546,9 @@
if opts.get('note'):
metadata['note'] = opts['note']
- obsolete.createmarkers(repo, [(old, (repo[newid],))], metadata=metadata,
- operation="uncommit")
+ replacements = {old.node(): [newid]}
+ scmutil.cleanupnodes(repo, replacements, operation="uncommit",
+ metadata=metadata)
phases.retractboundary(repo, tr, oldphase, [newid])
if opts.get('revert'):
hg.updaterepo(repo, newid, True)
@@ -557,7 +556,6 @@
with repo.dirstate.parentchange():
repo.dirstate.setparents(newid, node.nullid)
_uncommitdirstate(repo, old, match, interactive)
- updatebookmarks(newid)
if not repo[newid].files():
ui.warn(_("new changeset is empty\n"))
ui.status(_("(use 'hg prune .' to remove it)\n"))
@@ -776,14 +774,9 @@
root.p2().node()],
commitopts=commitopts)
phases.retractboundary(repo, tr, targetphase, [newid])
- obsolete.createmarkers(repo, [(ctx, (repo[newid],))
- for ctx in allctx], metadata=metadata,
- operation="fold")
- # move bookmarks from old nodes to the new one
- # XXX: we should make rewriteutil.rewrite() handle such cases
- for ctx in allctx:
- bmupdater = rewriteutil.bookmarksupdater(repo, ctx.node(), tr)
- bmupdater(newid)
+ replacements = {ctx.node(): [newid] for ctx in allctx}
+ scmutil.cleanupnodes(repo, replacements, operation="fold",
+ metadata=metadata)
tr.close()
finally:
tr.release()
@@ -1044,9 +1037,9 @@
msg = "please add --fold if you want to do a fold"
raise error.Abort(msg)
elif biject:
- relations = [(p, (s,)) for p, s in zip(precs, sucs)]
+ replacements = {p.node(): [s.node()] for p, s in zip(precs, sucs)}
else:
- relations = [(p, sucs) for p in precs]
+ replacements = {p.node(): [s.node() for s in sucs] for p in precs}
wdp = repo['.']
@@ -1106,14 +1099,8 @@
if opts.get('note'):
metadata['note'] = opts['note']
- # create markers
- obsolete.createmarkers(repo, relations, metadata=metadata,
- operation="prune")
-
- # informs that changeset have been pruned
- ui.status(_('%i changesets pruned\n') % len(precs))
-
precrevs = (precursor.rev() for precursor in precs)
+ moves = {}
for ctx in repo.unfiltered().set('bookmark() and %ld', precrevs):
# used to be:
#
@@ -1124,11 +1111,14 @@
# but then revset took a lazy arrow in the knee and became much
# slower. The new forms makes as much sense and a much faster.
for dest in ctx.ancestors():
- if not dest.obsolete():
- bookmarksupdater = rewriteutil.bookmarksupdater
- updatebookmarks = bookmarksupdater(repo, ctx.node(), tr)
- updatebookmarks(dest.node())
+ if not dest.obsolete() and dest.node() not in replacements:
+ moves[ctx.node()] = dest.node()
break
+ scmutil.cleanupnodes(repo, replacements, operation="prune", moves=moves,
+ metadata=metadata)
+
+ # informs that changeset have been pruned
+ ui.status(_('%i changesets pruned\n') % len(precs))
tr.close()
finally:
@@ -1397,7 +1387,7 @@
[('r', 'rev', '', _('revision to pick'), _('REV')),
('c', 'continue', False, 'continue interrupted pick'),
('a', 'abort', False, 'abort interrupted pick'),
- ],
+ ] + mergetoolopts,
_('[-r] rev'))
def cmdpick(ui, repo, *revs, **opts):
"""move a commit on the top of working directory parent and updates to it."""
@@ -1412,7 +1402,8 @@
if opts.get('rev'):
revs.append(opts['rev'])
- with repo.wlock(), repo.lock(), repo.transaction('pick'):
+ overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
+ with repo.wlock(), repo.lock(), repo.transaction('pick'), ui.configoverride(overrides, 'pick'):
pickstate = state.cmdstate(repo, path='pickstate')
pctx = repo['.']
@@ -1473,7 +1464,8 @@
if pickstate:
pickstate.delete()
newctx = repo[newnode] if newnode else pctx
- obsolete.createmarkers(repo, [(origctx, (newctx,))], operation="pick")
+ replacements = {origctx.node(): [newctx.node()]}
+ scmutil.cleanupnodes(repo, replacements, operation="pick")
if newnode is None:
ui.warn(_("note: picking %d:%s created no changes to commit\n") %
--- a/hgext3rd/evolve/evolvecmd.py Mon Feb 11 21:33:02 2019 +0800
+++ b/hgext3rd/evolve/evolvecmd.py Wed Feb 13 19:18:17 2019 +0800
@@ -18,8 +18,8 @@
context,
copies,
error,
+ encoding,
hg,
- lock as lockmod,
merge,
mergeutil,
node as nodemod,
@@ -71,11 +71,7 @@
else:
displayer = compat.changesetdisplayer(ui, repo,
{'template': shorttemplate})
- wlock = lock = tr = None
- try:
- wlock = repo.wlock()
- lock = repo.lock()
- tr = repo.transaction("evolve")
+ with repo.wlock(), repo.lock(), repo.transaction("evolve"):
if 'orphan' == category:
result = _solveunstable(ui, repo, ctx, evolvestate, displayer,
dryrun, confirm, progresscb,
@@ -89,10 +85,7 @@
dryrun, confirm, progresscb)
else:
assert False, "unknown trouble category: %s" % (category)
- tr.close()
return result
- finally:
- lockmod.release(tr, lock, wlock)
def _solveunstable(ui, repo, orig, evolvestate, displayer, dryrun=False,
confirm=False, progresscb=None, lastsolved=None):
@@ -382,6 +375,12 @@
evolvestate['other-divergent'] = other.node()
evolvestate['base'] = base.node()
+ # haspubdiv: to keep track if we are solving public content-divergence
+ haspubdiv = False
+ if not other.mutable():
+ haspubdiv = True
+ publicdiv = other
+ evolvestate['public-divergent'] = other.node()
# we don't handle merge content-divergent changesets yet
if len(other.parents()) > 1:
msg = _("skipping %s: %s changeset can't be "
@@ -499,8 +498,22 @@
_mergecontentdivergents(repo, progresscb, divergent, other, base,
evolvestate)
- return _completecontentdivergent(ui, repo, progresscb, divergent, other,
- base, evolvestate)
+ res, newnode = _completecontentdivergent(ui, repo, progresscb, divergent,
+ other, base, evolvestate)
+ if not haspubdiv:
+ return (res, newnode)
+ else:
+ # when we have content-divergence with a public cset: after completing
+ # content divergence resolution the resulting node will be phase
+ # divergent with that same public cset.
+ # here newnode is phase divergent, lets resolve this divergence.
+ if not res:
+ return (res, newnode)
+
+ prec = publicdiv
+ bumped = repo[newnode]
+ return _resolvephasedivergent(ui, repo, prec=prec, bumped=bumped,
+ tmpctx=bumped)
def _mergecontentdivergents(repo, progresscb, divergent, other, base,
evolvestate):
@@ -542,6 +555,13 @@
# whether to store the obsmarker in the evolvestate
storemarker = False
resparent = evolvestate['resolutionparent']
+
+ # whether we are solving public divergence
+ haspubdiv = False
+ if evolvestate.get('public-divergent'):
+ haspubdiv = True
+ npublicdiv = evolvestate['public-divergent']
+ publicdiv = repo[npublicdiv]
try:
with repo.dirstate.parentchange():
repo.dirstate.setparents(resparent, nodemod.nullid)
@@ -571,10 +591,17 @@
new = repo[newnode]
newnode = new.node()
hg.updaterepo(repo, new.rev(), False)
- obsolete.createmarkers(repo, [(divergent, (new,))], operation='evolve')
+ if haspubdiv and publicdiv == divergent:
+ bypassphase(repo, (divergent, new), operation='evolve')
+ else:
+ obsolete.createmarkers(repo, [(divergent, (new,))],
+ operation='evolve')
# creating markers and moving phases post-resolution
- obsolete.createmarkers(repo, [(other, (new,))], operation='evolve')
+ if haspubdiv and publicdiv == other:
+ bypassphase(repo, (other, new), operation='evolve')
+ else:
+ obsolete.createmarkers(repo, [(other, (new,))], operation='evolve')
if storemarker:
# storing the marker in the evolvestate
# we just store the precursors and successor pair for now, we might
@@ -587,6 +614,46 @@
finally:
repo.ui.restoreconfig(emtpycommitallowed)
+def bypassphase(repo, relation, flag=0, metadata=None, operation='evolve'):
+ """function to create a single obsmarker relation even for public csets
+ where relation should be a single pair (prec, succ)"""
+
+ # prepare metadata
+ if metadata is None:
+ metadata = {}
+ if 'user' not in metadata:
+ luser = repo.ui.config('devel', 'user.obsmarker') or repo.ui.username()
+ metadata['user'] = encoding.fromlocal(luser)
+ # Operation metadata handling
+ useoperation = repo.ui.configbool('experimental',
+ 'evolution.track-operation')
+ if useoperation and operation:
+ metadata['operation'] = operation
+
+ # Effect flag metadata handling
+ saveeffectflag = repo.ui.configbool('experimental',
+ 'evolution.effect-flags')
+ with repo.transaction('add-obsolescence-marker') as tr:
+ prec, succ = relation
+ nprec = prec.node()
+ npare = None
+ nsucs = [succ.node()]
+ if not nsucs:
+ npare = tuple(p.node() for p in prec.parents())
+ if nprec in nsucs:
+ raise error.Abort(_("changeset %s cannot obsolete itself") % prec)
+
+ if saveeffectflag:
+ # The effect flag is saved in a versioned field name for
+ # future evolution
+ effectflag = obsutil.geteffectflag(prec, (succ,))
+ metadata[obsutil.EFFECTFLAGFIELD] = "%d" % effectflag
+
+ # create markers
+ repo.obsstore.create(tr, nprec, nsucs, flag, parents=npare,
+ metadata=metadata, ui=repo.ui)
+ repo.filteredrevcache.clear()
+
def dirstatedance(repo, oldparent, newparent, match):
"""utility function to fix the dirstate when we change parents from
oldparent to newparent with a directory working directory using
@@ -1297,10 +1364,12 @@
compat.progress(ui, _('evolve'), None)
if not shouldupdate:
+ # Move back to startnode, or to its successor if the start node is
+ # obsolete (perhaps made obsolete by the current `hg evolve`)
unfi = repo.unfiltered()
succ = utility._singlesuccessor(repo, unfi[startnode])
hg.updaterepo(repo, repo[succ].node(), False)
- if repo['.'] != startnode:
+ if repo['.'].node() != startnode:
ui.status(_('working directory is now at %s\n') % repo['.'])
def divergentsets(repo, ctx):
@@ -1455,7 +1524,7 @@
contopt = opts['continue']
anyopt = opts['any']
allopt = opts['all']
- startnode = repo['.']
+ startnode = repo['.'].node()
dryrunopt = opts['dry_run']
confirmopt = opts['confirm']
revopt = opts['rev']
@@ -1552,7 +1621,7 @@
# cbor does not know how to serialize sets, using list for skippedrevs
stateopts = {'category': targetcat, 'replacements': {},
'revs': list(revs), 'confirm': confirmopt,
- 'startnode': startnode.node(), 'skippedrevs': [],
+ 'startnode': startnode, 'skippedrevs': [],
'command': 'evolve', 'orphanmerge': False,
'bookmarkchanges': [], 'temprevs': [], 'obsmarkers': []}
evolvestate.addopts(stateopts)
@@ -1599,8 +1668,9 @@
_cleanup(ui, repo, startnode, showprogress, shouldupdate)
def solveobswdp(ui, repo, opts):
+ """this function updates to the successor of obsolete wdir parent"""
oldid = repo['.'].node()
- startnode = repo['.']
+ startctx = repo['.']
dryrunopt = opts.get('dry_run', False)
displayer = compat.changesetdisplayer(ui, repo,
{'template': shorttemplate})
@@ -1623,7 +1693,7 @@
res = hg.update(repo, ctx.rev())
newid = ctx.node()
- if ctx != startnode:
+ if ctx != startctx:
with repo.wlock(), repo.lock(), repo.transaction('evolve') as tr:
bmupdater = rewriteutil.bookmarksupdater(repo, oldid, tr)
bmupdater(newid)
@@ -1819,7 +1889,18 @@
repo[base],
evolvestate)
evolvestate['replacements'][divergent] = ret[1]
+ # logic to continue the public content-divergent
+ publicdiv = evolvestate.get('public-divergent')
+ if publicdiv:
+ res, newnode = ret
+ if not res:
+ return (res, newnode)
+ prec = repo[publicdiv]
+ bumped = repo[newnode]
+ ret = _resolvephasedivergent(ui, repo, prec=prec, bumped=bumped,
+ tmpctx=bumped)
tr.close()
+ return ret
finally:
tr.release()
--- a/hgext3rd/evolve/metadata.py Mon Feb 11 21:33:02 2019 +0800
+++ b/hgext3rd/evolve/metadata.py Wed Feb 13 19:18:17 2019 +0800
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-__version__ = '8.4.1.dev'
+__version__ = '8.5.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/utility.py Mon Feb 11 21:33:02 2019 +0800
+++ b/hgext3rd/evolve/utility.py Wed Feb 13 19:18:17 2019 +0800
@@ -164,7 +164,7 @@
promptmsg = customheader + "\n"
for idx, rev in enumerate(revs):
curctx = repo[rev]
- revmsg = "%d: [%s] %s\n" % (idx, curctx,
+ revmsg = "%d: [%s] %s\n" % (idx + 1, curctx,
curctx.description().split("\n")[0])
promptmsg += revmsg
@@ -181,9 +181,9 @@
ui.write_err(_("invalid value '%s' entered for index\n") % idxselected)
return None
- if intidx >= len(revs) or intidx < 0:
+ if intidx > len(revs) or intidx <= 0:
# we can make this error message better
ui.write_err(_("invalid value '%d' entered for index\n") % intidx)
return None
- return revs[intidx]
+ return revs[intidx - 1]
--- a/hgext3rd/serverminitopic.py Mon Feb 11 21:33:02 2019 +0800
+++ b/hgext3rd/serverminitopic.py Wed Feb 13 19:18:17 2019 +0800
@@ -146,6 +146,10 @@
return hasminitopic(repo) and repo.filtername not in _publiconly
class _topiccache(branchmap.branchcache): # combine me with branchmap.branchcache
+ @classmethod
+ def fromfile(cls, repo):
+ orig = super(_topiccache, cls).fromfile
+ return wrapread(orig, repo)
def __init__(self, *args, **kwargs):
# super() call may fail otherwise
@@ -226,6 +230,12 @@
def uisetup(ui):
wrapclass(branchmap, 'branchcache', _topiccache)
- extensions.wrapfunction(branchmap, 'read', wrapread)
+ try:
+ # Mercurial 4.8 and older
+ extensions.wrapfunction(branchmap, 'read', wrapread)
+ except AttributeError:
+ # Mercurial 4.9; branchcache.fromfile now takes care of this
+ # which is alredy defined on _topiccache
+ pass
extensions.wrapfunction(wireproto, '_capabilities', wireprotocaps)
extensions.wrapfunction(context.changectx, 'branch', topicbranch)
--- a/hgext3rd/topic/__init__.py Mon Feb 11 21:33:02 2019 +0800
+++ b/hgext3rd/topic/__init__.py Wed Feb 13 19:18:17 2019 +0800
@@ -177,7 +177,7 @@
'topic.active': 'green',
}
-__version__ = '0.13.1.dev'
+__version__ = '0.14.0.dev'
testedwith = '4.4.2 4.5.2 4.6.2 4.7 4.8 4.9'
minimumhgversion = '4.4'
--- a/hgext3rd/topic/revset.py Mon Feb 11 21:33:02 2019 +0800
+++ b/hgext3rd/topic/revset.py Wed Feb 13 19:18:17 2019 +0800
@@ -108,7 +108,7 @@
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):
+ def stackrel(repo, subset, x, rel, z, 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
@@ -116,9 +116,25 @@
(e.g. when stack index is too high), this returns empty set to be more
revset-friendly.
"""
+ # hg 4.9 provides a number or None, hg 5.0 provides a tuple of tokens
+ if isinstance(z, tuple):
+ a, b = revset.getintrange(
+ z,
+ 'relation subscript must be an integer or a range',
+ 'relation subscript bounds must be integers',
+ None, None)
+ else:
+ a = b = z
+
s = revset.getset(repo, revset.fullreposet(repo), x)
if not s:
return revset.baseset()
+
+ def getrange(st, a, b):
+ start = 1 if a is None else a
+ end = len(st.revs) if b is None else b + 1
+ return range(start, end)
+
revs = []
for r in s:
topic = repo[r].topic()
@@ -126,32 +142,29 @@
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)
+ for n in getrange(st, a, b):
+ if abs(n) >= len(st.revs):
+ # also means stack base is not accessible with n < 0, which
+ # is by design
+ continue
+ if n == 0 and b != 0 and a != 0:
+ # quirk: we don't want stack base unless specifically asked
+ # for it (at least one of the indices is 0)
+ continue
+ rev = st.revs[n]
+ 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)
+ def topicrel(repo, subset, x, *args):
+ subset &= topicset(repo, subset, x)
+ return revset.generationsrel(repo, subset, x, *args)
revset.subscriptrelations['topic'] = topicrel
revset.subscriptrelations['t'] = topicrel
--- a/hgext3rd/topic/topicmap.py Mon Feb 11 21:33:02 2019 +0800
+++ b/hgext3rd/topic/topicmap.py Wed Feb 13 19:18:17 2019 +0800
@@ -117,7 +117,21 @@
class topiccache(_topiccache, branchmap.branchcache):
pass
branchmap.branchcache = topiccache
- extensions.wrapfunction(branchmap, 'updatecache', _wrapupdatebmcache)
+
+ try:
+ # Mercurial 4.9
+ class remotetopiccache(_topiccache, branchmap.remotebranchcache):
+ pass
+ branchmap.remotebranchcache = remotetopiccache
+
+ def _wrapupdatebmcachemethod(orig, self, repo):
+ # pass in the bound method as the original
+ return _wrapupdatebmcache(orig.__get__(self), repo)
+ extensions.wrapfunction(branchmap.BranchMapCache, 'updatecache', _wrapupdatebmcachemethod)
+ except AttributeError:
+ # Mercurial 4.8 and before
+ extensions.wrapfunction(branchmap, 'updatecache', _wrapupdatebmcache)
+
def _wrapupdatebmcache(orig, repo):
previous = getattr(repo, '_autobranchmaptopic', False)
--- a/tests/test-evolve-continue.t Mon Feb 11 21:33:02 2019 +0800
+++ b/tests/test-evolve-continue.t Wed Feb 13 19:18:17 2019 +0800
@@ -127,6 +127,7 @@
$ hg evolve --continue
evolving 7:ad0a59d83efe "added e"
evolution of 7:ad0a59d83efe created no changes to commit
+ working directory is now at 00a5c774cc37
$ hg glog
@ 8:00a5c774cc37 added d
--- a/tests/test-evolve-issue5832.t Mon Feb 11 21:33:02 2019 +0800
+++ b/tests/test-evolve-issue5832.t Wed Feb 13 19:18:17 2019 +0800
@@ -112,17 +112,17 @@
Resolving instability using `hg evolve`
$ hg evolve --any --all --config ui.interactive=True <<EOF
- > 0
+ > 1
> EOF
move:[2] added b
atop:[5] added a
move:[4] merge commit
ancestor '7235ef625ea3' split over multiple topological branches.
choose an evolve destination:
- 0: [62fb70414f99] added c
- 1: [5841d7cf9893] added d
+ 1: [62fb70414f99] added c
+ 2: [5841d7cf9893] added d
q: quit the prompt
- enter the index of the revision you want to select: 0
+ enter the index of the revision you want to select: 1
move:[9] merge commit
atop:[6] added c
working directory is now at 28a0775ac832
@@ -253,17 +253,17 @@
could not solve instability, ambiguous destination: parent split across two branches
$ hg evolve --any --all --config ui.interactive=True <<EOF
- > 1
+ > 2
> EOF
move:[2] added b
atop:[6] added a
move:[4] merge commit
ancestor 'cdf2ea1b9312' split over multiple topological branches.
choose an evolve destination:
- 0: [62fb70414f99] added c
- 1: [5841d7cf9893] added d
+ 1: [62fb70414f99] added c
+ 2: [5841d7cf9893] added d
q: quit the prompt
- enter the index of the revision you want to select: 1
+ enter the index of the revision you want to select: 2
move:[10] merge commit
atop:[8] added d
working directory is now at 460e6e72b7f9
@@ -398,16 +398,16 @@
could not solve instability, ambiguous destination: parent split across two branches
$ hg evolve --any --all --config ui.interactive=True <<EOF
- > 1
+ > 2
> EOF
move:[2] added b
atop:[6] added a
ancestor 'b9b387427a53' split over multiple topological branches.
choose an evolve destination:
- 0: [62fb70414f99] added c
- 1: [5841d7cf9893] added d
+ 1: [62fb70414f99] added c
+ 2: [5841d7cf9893] added d
q: quit the prompt
- enter the index of the revision you want to select: 1
+ enter the index of the revision you want to select: 2
move:[4] merge commit
atop:[8] added d
move:[10] merge commit
--- a/tests/test-evolve-orphan-split.t Mon Feb 11 21:33:02 2019 +0800
+++ b/tests/test-evolve-orphan-split.t Wed Feb 13 19:18:17 2019 +0800
@@ -182,27 +182,27 @@
() draft
$ hg evolve --dry-run <<EOF
- > 0
+ > 1
> EOF
ancestor 'd48a30875f01' split over multiple topological branches.
choose an evolve destination:
- 0: [f2632392aefe] added a b c
- 1: [7f87764e5b64] added a b c
+ 1: [f2632392aefe] added a b c
+ 2: [7f87764e5b64] added a b c
q: quit the prompt
- enter the index of the revision you want to select: 0
+ enter the index of the revision you want to select: 1
move:[7] added d
atop:[8] added a b c
hg rebase -r d48a30875f01 -d f2632392aefe
$ hg evolve --dry-run <<EOF
- > 1
+ > 2
> EOF
ancestor 'd48a30875f01' split over multiple topological branches.
choose an evolve destination:
- 0: [f2632392aefe] added a b c
- 1: [7f87764e5b64] added a b c
+ 1: [f2632392aefe] added a b c
+ 2: [7f87764e5b64] added a b c
q: quit the prompt
- enter the index of the revision you want to select: 1
+ enter the index of the revision you want to select: 2
move:[7] added d
atop:[10] added a b c
hg rebase -r d48a30875f01 -d 7f87764e5b64
@@ -215,8 +215,8 @@
> EOF
ancestor 'd48a30875f01' split over multiple topological branches.
choose an evolve destination:
- 0: [f2632392aefe] added a b c
- 1: [7f87764e5b64] added a b c
+ 1: [f2632392aefe] added a b c
+ 2: [7f87764e5b64] added a b c
q: quit the prompt
enter the index of the revision you want to select: foo
invalid value 'foo' entered for index
@@ -227,8 +227,8 @@
> EOF
ancestor 'd48a30875f01' split over multiple topological branches.
choose an evolve destination:
- 0: [f2632392aefe] added a b c
- 1: [7f87764e5b64] added a b c
+ 1: [f2632392aefe] added a b c
+ 2: [7f87764e5b64] added a b c
q: quit the prompt
enter the index of the revision you want to select: 4
invalid value '4' entered for index
@@ -239,8 +239,8 @@
> EOF
ancestor 'd48a30875f01' split over multiple topological branches.
choose an evolve destination:
- 0: [f2632392aefe] added a b c
- 1: [7f87764e5b64] added a b c
+ 1: [f2632392aefe] added a b c
+ 2: [7f87764e5b64] added a b c
q: quit the prompt
enter the index of the revision you want to select: -1
invalid value '-1' entered for index
@@ -251,8 +251,8 @@
> EOF
ancestor 'd48a30875f01' split over multiple topological branches.
choose an evolve destination:
- 0: [f2632392aefe] added a b c
- 1: [7f87764e5b64] added a b c
+ 1: [f2632392aefe] added a b c
+ 2: [7f87764e5b64] added a b c
q: quit the prompt
enter the index of the revision you want to select: q
could not solve instability, ambiguous destination: parent split across two branches
@@ -264,10 +264,10 @@
> EOF
ancestor 'd48a30875f01' split over multiple topological branches.
choose an evolve destination:
- 0: [f2632392aefe] added a b c
- 1: [7f87764e5b64] added a b c
+ 1: [f2632392aefe] added a b c
+ 2: [7f87764e5b64] added a b c
q: quit the prompt
enter the index of the revision you want to select: 1
move:[7] added d
- atop:[10] added a b c
- working directory is now at 1c6caa7c902a
+ atop:[8] added a b c
+ working directory is now at 71e4d45a7aaa
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-public-content-divergent.t Wed Feb 13 19:18:17 2019 +0800
@@ -0,0 +1,365 @@
+Test for handling of content divergence with public cset using `hg evolve`
+==========================================================================
+
+Setup
+=====
+ $ cat >> $HGRCPATH <<EOF
+ > [alias]
+ > glog = log -GT "{rev}:{node|short} {desc|firstline}\n {phase} {troubles}\n\n"
+ > [phases]
+ > publish = False
+ > [extensions]
+ > rebase =
+ > EOF
+ $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+
+Testing the case when both divergent cset are on the same parent and no-conflict in merging:
+-------------------------------------------------------------------------------------
+
+Prepare the repository:
+
+ $ hg init pubdiv
+ $ cd pubdiv
+ $ for ch in a b; do
+ > echo $ch > $ch;
+ > hg ci -Aqm "added "$ch;
+ > done;
+ $ hg glog
+ @ 1:5f6d8a4bf34a added b
+ | draft
+ |
+ o 0:9092f1db7931 added a
+ draft
+
+
+Make an amend and change phase to public:
+
+ $ sed -i "1 i I am first" b
+ $ hg amend
+ $ hg phase --public
+
+Amend again to create a cset divergent to public one:
+
+ $ hg up 1 --hidden -q
+ updated to hidden changeset 5f6d8a4bf34a
+ (hidden revision '5f6d8a4bf34a' was rewritten as: 44f360db368f)
+ working directory parent is obsolete! (5f6d8a4bf34a)
+
+ $ echo "I am second" >> b
+ $ hg ci --amend -m "updated b"
+ 1 new content-divergent changesets
+
+ $ hg glog
+ @ 3:dcdaf152280a updated b
+ | draft content-divergent
+ |
+ | o 2:44f360db368f added b
+ |/ public
+ |
+ o 0:9092f1db7931 added a
+ public
+
+
+Lets resolve the public content-divergence:
+
+ $ hg evolve --content-divergent
+ merge:[3] updated b
+ with: [2] added b
+ base: [1] added b
+ merging "other" content-divergent changeset '44f360db368f'
+ merging b
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ computing new diff
+ committed as c1aa9cfb6cf8
+ working directory is now at c1aa9cfb6cf8
+
+Following graph log shows that it correctly merged the two divergent csets:
+
+ $ hg glog -p
+ @ 5:c1aa9cfb6cf8 phase-divergent update to 44f360db368f:
+ | draft
+ |
+ | diff -r 44f360db368f -r c1aa9cfb6cf8 b
+ | --- a/b Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ | @@ -1,2 +1,3 @@
+ | I am first
+ | b
+ | +I am second
+ |
+ o 2:44f360db368f added b
+ | public
+ |
+ | diff -r 9092f1db7931 -r 44f360db368f b
+ | --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ | @@ -0,0 +1,2 @@
+ | +I am first
+ | +b
+ |
+ o 0:9092f1db7931 added a
+ public
+
+ diff -r 000000000000 -r 9092f1db7931 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+ $ hg evolve -l
+
+ $ cd ..
+
+Testing the case when both divergent cset has same parent and has conflict in merging:
+------------------------------------------------------------------------------
+
+Prepare the repository:
+
+ $ hg init pubdiv1
+ $ cd pubdiv1
+ $ for ch in a b; do
+ > echo $ch > $ch;
+ > hg ci -Aqm "added "$ch;
+ > done;
+ $ hg glog
+ @ 1:5f6d8a4bf34a added b
+ | draft
+ |
+ o 0:9092f1db7931 added a
+ draft
+
+
+Make an amend and change phase to public:
+
+ $ echo "I am foo" > b
+ $ hg amend
+ $ hg phase --public
+
+Amend again to create a cset divergent to public one:
+
+ $ hg up 1 --hidden -q
+ updated to hidden changeset 5f6d8a4bf34a
+ (hidden revision '5f6d8a4bf34a' was rewritten as: 580f2d01e52c)
+ working directory parent is obsolete! (5f6d8a4bf34a)
+
+ $ echo "I am bar" > b
+ $ hg ci --amend -m "updated b"
+ 1 new content-divergent changesets
+
+ $ hg glog
+ @ 3:0e805383168e updated b
+ | draft content-divergent
+ |
+ | o 2:580f2d01e52c added b
+ |/ public
+ |
+ o 0:9092f1db7931 added a
+ public
+
+
+Lets resolve the divergence:
+
+ $ hg evolve --content-divergent
+ merge:[3] updated b
+ with: [2] added b
+ base: [1] added b
+ merging "other" content-divergent changeset '580f2d01e52c'
+ merging b
+ warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ fix conflicts and see `hg help evolve.interrupted`
+ [1]
+
+ $ echo "I am foobar" > b
+ $ hg resolve -m --tool union
+ (no more unresolved files)
+ continue: hg evolve --continue
+ $ hg evolve --continue
+ computing new diff
+ committed as 1a739394e9d4
+ working directory is now at 1a739394e9d4
+
+ $ hg glog
+ @ 5:1a739394e9d4 phase-divergent update to 580f2d01e52c:
+ | draft
+ |
+ o 2:580f2d01e52c added b
+ | public
+ |
+ o 0:9092f1db7931 added a
+ public
+
+Testing the case when divergence is not created by actual diff change, but because of rebasing:
+------------------------------------------------------------------------------------------------
+
+Prepare the repo:
+
+ $ cd ..
+ $ hg init rebasediv
+ $ cd rebasediv
+ $ for ch in a b c; do
+ > echo $ch > $ch;
+ > hg ci -Am "added "$ch;
+ > done;
+ adding a
+ adding b
+ adding c
+
+ $ hg glog
+ @ 2:155349b645be added c
+ | draft
+ |
+ o 1:5f6d8a4bf34a added b
+ | draft
+ |
+ o 0:9092f1db7931 added a
+ draft
+
+
+On server side: a new cset is added based on rev 1 and rev 2 is rebased on newly added cset:
+
+ $ hg up .^ -q
+ $ echo d > d
+ $ hg ci -Am "added d"
+ adding d
+ created new head
+
+ $ hg rebase -r 2 -d .
+ rebasing 2:155349b645be "added c"
+
+ $ hg glog
+ o 4:c0d7ee6604ea added c
+ | draft
+ |
+ @ 3:c9241b0f2d5b added d
+ | draft
+ |
+ o 1:5f6d8a4bf34a added b
+ | draft
+ |
+ o 0:9092f1db7931 added a
+ draft
+
+
+On user side: user has not pulled yet and amended the rev 2 which created the divergence after pull:
+ $ hg up 2 --hidden -q
+ updated to hidden changeset 155349b645be
+ (hidden revision '155349b645be' was rewritten as: c0d7ee6604ea)
+ working directory parent is obsolete! (155349b645be)
+
+ $ echo cc >> c
+ $ hg ci --amend -m "updated c"
+ 2 new content-divergent changesets
+
+Lets change the phase to --public of branch which is pulled from server:
+ $ hg phase --public -r 4
+ $ hg glog -p
+ @ 5:f5f9b4fc8b77 updated c
+ | draft content-divergent
+ |
+ | diff -r 5f6d8a4bf34a -r f5f9b4fc8b77 c
+ | --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/c Thu Jan 01 00:00:00 1970 +0000
+ | @@ -0,0 +1,2 @@
+ | +c
+ | +cc
+ |
+ | o 4:c0d7ee6604ea added c
+ | | public
+ | |
+ | | diff -r c9241b0f2d5b -r c0d7ee6604ea c
+ | | --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ | | +++ b/c Thu Jan 01 00:00:00 1970 +0000
+ | | @@ -0,0 +1,1 @@
+ | | +c
+ | |
+ | o 3:c9241b0f2d5b added d
+ |/ public
+ |
+ | diff -r 5f6d8a4bf34a -r c9241b0f2d5b d
+ | --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/d Thu Jan 01 00:00:00 1970 +0000
+ | @@ -0,0 +1,1 @@
+ | +d
+ |
+ o 1:5f6d8a4bf34a added b
+ | public
+ |
+ | diff -r 9092f1db7931 -r 5f6d8a4bf34a b
+ | --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ | @@ -0,0 +1,1 @@
+ | +b
+ |
+ o 0:9092f1db7931 added a
+ public
+
+ diff -r 000000000000 -r 9092f1db7931 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+
+Evolve:
+ $ hg evolve --content-divergent
+ merge:[4] added c
+ with: [5] updated c
+ base: [2] added c
+ rebasing "other" content-divergent changeset f5f9b4fc8b77 on c9241b0f2d5b
+ updating to "local" side of the conflict: c0d7ee6604ea
+ merging "other" content-divergent changeset 'c3d442d80993'
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ computing new diff
+ committed as 3b336cbee992
+ working directory is now at 3b336cbee992
+
+ $ hg glog -p
+ @ 8:3b336cbee992 phase-divergent update to c0d7ee6604ea:
+ | draft
+ |
+ | diff -r c0d7ee6604ea -r 3b336cbee992 c
+ | --- a/c Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/c Thu Jan 01 00:00:00 1970 +0000
+ | @@ -1,1 +1,2 @@
+ | c
+ | +cc
+ |
+ o 4:c0d7ee6604ea added c
+ | public
+ |
+ | diff -r c9241b0f2d5b -r c0d7ee6604ea c
+ | --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/c Thu Jan 01 00:00:00 1970 +0000
+ | @@ -0,0 +1,1 @@
+ | +c
+ |
+ o 3:c9241b0f2d5b added d
+ | public
+ |
+ | diff -r 5f6d8a4bf34a -r c9241b0f2d5b d
+ | --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/d Thu Jan 01 00:00:00 1970 +0000
+ | @@ -0,0 +1,1 @@
+ | +d
+ |
+ o 1:5f6d8a4bf34a added b
+ | public
+ |
+ | diff -r 9092f1db7931 -r 5f6d8a4bf34a b
+ | --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ | +++ b/b Thu Jan 01 00:00:00 1970 +0000
+ | @@ -0,0 +1,1 @@
+ | +b
+ |
+ o 0:9092f1db7931 added a
+ public
+
+ diff -r 000000000000 -r 9092f1db7931 a
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/a Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +a
+
+Check that we don't have any troubled cset now:
+ $ hg evolve -l
--- a/tests/test-grab.t Mon Feb 11 21:33:02 2019 +0800
+++ b/tests/test-grab.t Wed Feb 13 19:18:17 2019 +0800
@@ -24,9 +24,10 @@
options:
- -r --rev REV 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
+ -t --tool TOOL specify merge tool
(some details hidden, use --verbose to show complete help)
--- a/tests/test-prev-next.t Mon Feb 11 21:33:02 2019 +0800
+++ b/tests/test-prev-next.t Wed Feb 13 19:18:17 2019 +0800
@@ -213,13 +213,13 @@
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
[3] added b (2)
$ hg next <<EOF
- > 1
+ > 2
> EOF
ambiguous next changeset, choose one to update:
- 0: [e3b6d5df389b] added c
- 1: [9df671ccd2c7] added d
+ 1: [e3b6d5df389b] added c
+ 2: [9df671ccd2c7] added d
q: quit the prompt
- enter the index of the revision you want to select: 1
+ enter the index of the revision you want to select: 2
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[5] added d
@@ -236,13 +236,13 @@
(2 unstable changesets to be evolved here, do you want --evolve?)
[1]
$ hg next --evolve <<EOF
- > 0
+ > 1
> EOF
ambiguous next (unstable) changeset, choose one to evolve and update:
- 0: [e3b6d5df389b] added c
- 1: [9df671ccd2c7] added d
+ 1: [e3b6d5df389b] added c
+ 2: [9df671ccd2c7] added d
q: quit the prompt
- enter the index of the revision you want to select: 0
+ enter the index of the revision you want to select: 1
move:[4] added c
atop:[6] added b (3)
working directory now at 5ce67c2407b0
@@ -284,8 +284,8 @@
> q
> EOF
multiple parents, choose one to update:
- 0: [47ea25be8aea] added d
- 1: [5ce67c2407b0] added c
+ 1: [47ea25be8aea] added d
+ 2: [5ce67c2407b0] added c
q: quit the prompt
enter the index of the revision you want to select: q
[8] added d
@@ -300,13 +300,13 @@
[1]
$ hg prev <<EOF
- > 1
+ > 2
> EOF
multiple parents, choose one to update:
- 0: [47ea25be8aea] added d
- 1: [5ce67c2407b0] added c
+ 1: [47ea25be8aea] added d
+ 2: [5ce67c2407b0] added c
q: quit the prompt
- enter the index of the revision you want to select: 1
+ enter the index of the revision you want to select: 2
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
[7] added c
--- a/tests/test-split.t Mon Feb 11 21:33:02 2019 +0800
+++ b/tests/test-split.t Wed Feb 13 19:18:17 2019 +0800
@@ -19,6 +19,8 @@
> [diff]
> git = 1
> unified = 0
+ > [commands]
+ > commit.interactive.unified = 0
> [ui]
> interactive = true
> [extensions]
--- a/tests/test-topic.t Mon Feb 11 21:33:02 2019 +0800
+++ b/tests/test-topic.t Wed Feb 13 19:18:17 2019 +0800
@@ -860,6 +860,10 @@
3: featureA
$ tlog 'featureA#topic[0]'
3: featureA
+ $ tlog 'featureA#topic[:]'
+ 1: featureA
+ 2: featureA
+ 3: featureA
$ tlog '2#t[-2]'
$ tlog '2#t[-1]'
@@ -869,6 +873,10 @@
$ tlog '2#t[1]'
3: featureA
$ tlog '2#t[2]'
+ $ tlog '2#t[-1:1]'
+ 1: featureA
+ 2: featureA
+ 3: featureA
stack subscript relation
@@ -898,6 +906,28 @@
$ tlog 'featureA#s[0]'
0:
+ $ tlog 'featureA#s[0:0]'
+ 0:
+ $ tlog 'featureA#s[:]'
+ 1: featureA
+ 2: featureA
+ 3: featureA
+ $ tlog 'featureA#s[2:]'
+ 2: featureA
+ 3: featureA
+ $ tlog 'featureA#s[:2]'
+ 1: featureA
+ 2: featureA
+ $ tlog 'featureA#s[0:1]'
+ 0:
+ 1: featureA
+ $ tlog 'featureA#s[-1:0]'
+ 0:
+ 3: featureA
+ $ tlog 'featureA#s[-3:3]'
+ 1: featureA
+ 2: featureA
+ 3: featureA
$ tlog 'featureA#s[1] and featureA#s[-3]'
1: featureA
$ tlog 'featureA#s[2] and featureA#s[-2]'