--- a/README Sat Oct 08 15:49:12 2016 +0200
+++ b/README Sun Oct 16 20:29:27 2016 +0200
@@ -63,6 +63,9 @@
5.4.2 --
- Fix erroneous manifest computation when solving 'bumped' changeset.
+ - split: avoid crash on empty commit (issue5191),
+ - next: improve locking to avoid issue with working copy parent (issue5244)
+ - prev: improve locking to avoid issue with working copy parent (issue5244)
5.4.1 -- 2016-08-01
--- a/hgext/evolve.py Sat Oct 08 15:49:12 2016 +0200
+++ b/hgext/evolve.py Sun Oct 16 20:29:27 2016 +0200
@@ -2213,57 +2213,63 @@
"""update to parent revision
Displays the summary line of the destination for clarity."""
- wkctx = repo[None]
- wparents = wkctx.parents()
+ wlock = None
dryrunopt = opts['dry_run']
- if len(wparents) != 1:
- raise error.Abort('merge in progress')
- if not opts['merge']:
- try:
- cmdutil.bailifchanged(repo)
- except error.Abort as exc:
- exc.hint = _('do you want --merge?')
- raise
-
- parents = wparents[0].parents()
- topic = getattr(repo, 'currenttopic', '')
- if topic and not opts.get("no_topic", False):
- parents = [ctx for ctx in parents if ctx.topic() == topic]
- displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
- if not parents:
- ui.warn(_('no parent in topic "%s"\n') % topic)
- ui.warn(_('(do you want --no-topic)\n'))
- elif len(parents) == 1:
- p = parents[0]
- bm = bmactive(repo)
- shouldmove = opts.get('move_bookmark') and bm is not None
- if dryrunopt:
- ui.write(('hg update %s;\n' % p.rev()))
- if shouldmove:
- ui.write(('hg bookmark %s -r %s;\n' % (bm, p.rev())))
+ if not dryrunopt:
+ wlock = repo.wlock()
+ try:
+ wkctx = repo[None]
+ wparents = wkctx.parents()
+ if len(wparents) != 1:
+ raise error.Abort('merge in progress')
+ if not opts['merge']:
+ try:
+ cmdutil.bailifchanged(repo)
+ except error.Abort as exc:
+ exc.hint = _('do you want --merge?')
+ raise
+
+ parents = wparents[0].parents()
+ topic = getattr(repo, 'currenttopic', '')
+ if topic and not opts.get("no_topic", False):
+ parents = [ctx for ctx in parents if ctx.topic() == topic]
+ displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
+ if not parents:
+ ui.warn(_('no parent in topic "%s"\n') % topic)
+ ui.warn(_('(do you want --no-topic)\n'))
+ elif len(parents) == 1:
+ p = parents[0]
+ bm = bmactive(repo)
+ shouldmove = opts.get('move_bookmark') and bm is not None
+ if dryrunopt:
+ ui.write(('hg update %s;\n' % p.rev()))
+ if shouldmove:
+ ui.write(('hg bookmark %s -r %s;\n' % (bm, p.rev())))
+ else:
+ ret = hg.update(repo, p.rev())
+ if not ret:
+ tr = lock = None
+ try:
+ lock = repo.lock()
+ tr = repo.transaction('previous')
+ if shouldmove:
+ repo._bookmarks[bm] = p.node()
+ repo._bookmarks.recordchange(tr)
+ else:
+ bmdeactivate(repo)
+ tr.close()
+ finally:
+ lockmod.release(tr, lock)
+
+ displayer.show(p)
+ return 0
else:
- ret = hg.update(repo, p.rev())
- if not ret:
- tr = lock = None
- wlock = repo.wlock()
- try:
- lock = repo.lock()
- tr = repo.transaction('previous')
- if shouldmove:
- repo._bookmarks[bm] = p.node()
- repo._bookmarks.recordchange(tr)
- else:
- bmdeactivate(repo)
- tr.close()
- finally:
- lockmod.release(tr, lock, wlock)
- displayer.show(p)
- return 0
- else:
- for p in parents:
- displayer.show(p)
- ui.warn(_('multiple parents, explicitly update to one\n'))
- return 1
+ for p in parents:
+ displayer.show(p)
+ ui.warn(_('multiple parents, explicitly update to one\n'))
+ return 1
+ finally:
+ lockmod.release(wlock)
@command('^next',
[('B', 'move-bookmark', False,
@@ -2281,91 +2287,96 @@
Displays the summary line of the destination for clarity.
"""
- wkctx = repo[None]
- wparents = wkctx.parents()
+ wlock = None
dryrunopt = opts['dry_run']
- if len(wparents) != 1:
- raise error.Abort('merge in progress')
- if not opts['merge']:
- 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 = getattr(repo, 'currenttopic', '')
- filtered = []
- if topic and not opts.get("no_topic", False):
- filtered = [ctx for ctx in children if ctx.topic() != topic]
- # XXX N-square membership on children
- children = [ctx for ctx in children if ctx not in filtered]
- displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
- if len(children) == 1:
- c = children[0]
- bm = bmactive(repo)
- shouldmove = opts.get('move_bookmark') and bm is not None
- if dryrunopt:
- ui.write(('hg update %s;\n' % c.rev()))
- if shouldmove:
- ui.write(('hg bookmark %s -r %s;\n' % (bm, c.rev())))
+ if not dryrunopt:
+ wlock = repo.wlock()
+ try:
+ wkctx = repo[None]
+ wparents = wkctx.parents()
+ if len(wparents) != 1:
+ raise error.Abort('merge in progress')
+ if not opts['merge']:
+ 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 = getattr(repo, 'currenttopic', '')
+ filtered = []
+ if topic and not opts.get("no_topic", False):
+ filtered = [ctx for ctx in children if ctx.topic() != topic]
+ # XXX N-square membership on children
+ children = [ctx for ctx in children if ctx not in filtered]
+ displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
+ if len(children) == 1:
+ c = children[0]
+ bm = bmactive(repo)
+ shouldmove = opts.get('move_bookmark') and bm is not None
+ if dryrunopt:
+ ui.write(('hg update %s;\n' % c.rev()))
+ if shouldmove:
+ ui.write(('hg bookmark %s -r %s;\n' % (bm, c.rev())))
+ else:
+ ret = hg.update(repo, c.rev())
+ if not ret:
+ lock = tr = None
+ try:
+ lock = repo.lock()
+ tr = repo.transaction('next')
+ if shouldmove:
+ repo._bookmarks[bm] = c.node()
+ repo._bookmarks.recordchange(tr)
+ else:
+ bmdeactivate(repo)
+ tr.close()
+ finally:
+ lockmod.release(tr, lock)
+ displayer.show(c)
+ result = 0
+ elif children:
+ ui.warn(_("ambigious next changeset:\n"))
+ for c in children:
+ displayer.show(c)
+ ui.warn(_('explicitly update to one of them\n'))
+ result = 1
else:
- ret = hg.update(repo, c.rev())
- if not ret:
- lock = tr = None
- wlock = repo.wlock()
- try:
- lock = repo.lock()
- tr = repo.transaction('next')
- if shouldmove:
- repo._bookmarks[bm] = c.node()
- repo._bookmarks.recordchange(tr)
- else:
- bmdeactivate(repo)
- tr.close()
- finally:
- lockmod.release(tr, lock, wlock)
- displayer.show(c)
- result = 0
- elif children:
- ui.warn(_("ambigious next changeset:\n"))
- for c in children:
- displayer.show(c)
- ui.warn(_('explicitly update to one of them\n'))
- result = 1
- else:
- aspchildren = _aspiringchildren(repo, [repo['.'].rev()])
- if topic:
- filtered.extend(repo[c] for c in children
- if repo[c].topic() != topic)
- # XXX N-square membership on children
- 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)
- ui.warn(_('do you want --no-topic\n'))
+ aspchildren = _aspiringchildren(repo, [repo['.'].rev()])
+ if topic:
+ filtered.extend(repo[c] for c in children
+ if repo[c].topic() != topic)
+ # XXX N-square membership on children
+ 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)
+ ui.warn(_('do you want --no-topic\n'))
+ else:
+ ui.warn(_('no children\n'))
+ if aspchildren:
+ msg = _('(%i unstable changesets to be evolved here, '
+ 'do you want --evolve?)\n')
+ ui.warn(msg % len(aspchildren))
+ result = 1
+ elif 1 < len(aspchildren):
+ ui.warn(_("ambigious next (unstable) changeset:\n"))
+ for c in aspchildren:
+ displayer.show(repo[c])
+ ui.warn(_('(run "hg evolve --rev REV" on one of them)\n'))
+ return 1
else:
- ui.warn(_('no children\n'))
- if aspchildren:
- msg = _('(%i unstable changesets to be evolved here, '
- 'do you want --evolve?)\n')
- ui.warn(msg % len(aspchildren))
- result = 1
- elif 1 < len(aspchildren):
- ui.warn(_("ambigious next (unstable) changeset:\n"))
- for c in aspchildren:
- displayer.show(repo[c])
- ui.warn(_('(run "hg evolve --rev REV" on one of them)\n'))
+ cmdutil.bailifchanged(repo)
+ result = _solveone(ui, repo, repo[aspchildren[0]], dryrunopt,
+ False, lambda:None, category='unstable')
+ if not result:
+ ui.status(_('working directory now at %s\n') % repo['.'])
+ return result
return 1
- else:
- cmdutil.bailifchanged(repo)
- result = _solveone(ui, repo, repo[aspchildren[0]], dryrunopt,
- False, lambda:None, category='unstable')
- if not result:
- ui.status(_('working directory now at %s\n') % repo['.'])
- return result
- return 1
- return result
+ return result
+ finally:
+ lockmod.release(wlock)
def _reachablefrombookmark(repo, revs, bookmarks):
"""filter revisions and bookmarks reachable from the given bookmark
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/fake-editor.sh Sun Oct 16 20:29:27 2016 +0200
@@ -0,0 +1,3 @@
+#!/bin/sh
+sleep 5
+echo "new desc" >> $1
--- a/tests/test-prev-next.t Sat Oct 08 15:49:12 2016 +0200
+++ b/tests/test-prev-next.t Sun Oct 16 20:29:27 2016 +0200
@@ -206,3 +206,34 @@
move:[5] added d
atop:[6] added b (3)
working directory is now at 47ea25be8aea
+
+prev and next should lock properly against other commands
+
+ $ hg init repo
+ $ cd repo
+ $ HGEDITOR=${TESTDIR}/fake-editor.sh
+ $ echo hi > foo
+ $ hg ci -Am 'one'
+ adding foo
+ $ echo bye > foo
+ $ hg ci -Am 'two'
+
+ $ hg amend --edit &
+ $ sleep 1
+ $ hg prev
+ waiting for lock on working directory of $TESTTMP/repo held by process '*' on host '*' (glob)
+ got lock after [4-6] seconds (re)
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ [0] one
+ $ wait
+
+ $ hg amend --edit &
+ $ sleep 1
+ $ hg next --evolve
+ waiting for lock on working directory of $TESTTMP/repo held by process '*' on host '*' (glob)
+ 1 new unstable changesets
+ got lock after [4-6] seconds (re)
+ move:[2] two
+ atop:[3] one
+ working directory now at a7d885c75614
+ $ wait