--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/directaccess.py Thu Jun 25 17:37:43 2015 -0700
@@ -0,0 +1,175 @@
+""" This extension provides direct access
+It is the ability to refer and access hidden sha in commands provided that you
+know their value.
+For example hg log -r xxx where xxx is a commit has should work whether xxx is
+hidden or not as we assume that the user knows what he is doing when referring
+to xxx.
+"""
+from mercurial import extensions
+from mercurial import cmdutil
+from mercurial import repoview
+from mercurial import branchmap
+from mercurial import revset
+from mercurial import error
+from mercurial import commands
+from mercurial import hg
+from mercurial.i18n import _
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+
+# By default, all the commands have directaccess with warnings
+# List of commands that have no directaccess and directaccess with no warning
+directaccesslevel = [
+ # Format:
+ # ('nowarning', 'evolve', 'prune'),
+ # means: no directaccess warning, for the command in evolve named prune
+ #
+ # ('error', None, 'serve'),
+ # means: no directaccess for the command in core named serve
+ #
+ # The list is ordered alphabetically by command names, starting with all
+ # the commands in core then all the commands in the extensions
+ #
+ # The general guideline is:
+ # - remove directaccess warnings for read only commands
+ # - no direct access for commands with consequences outside of the repo
+ # - leave directaccess warnings for all the other commands
+ #
+ ('nowarning', None, 'annotate'),
+ ('nowarning', None, 'archive'),
+ ('nowarning', None, 'bisect'),
+ ('nowarning', None, 'bookmarks'),
+ ('nowarning', None, 'bundle'),
+ ('nowarning', None, 'cat'),
+ ('nowarning', None, 'diff'),
+ ('nowarning', None, 'export'),
+ ('nowarning', None, 'identify'),
+ ('nowarning', None, 'incoming'),
+ ('nowarning', None, 'log'),
+ ('nowarning', None, 'manifest'),
+ ('error', None, 'outgoing'), # confusing if push errors and not outgoing
+ ('error', None, 'push'), # destructive
+ ('nowarning', None, 'revert'),
+ ('error', None, 'serve'),
+ ('nowarning', None, 'tags'),
+ ('nowarning', None, 'unbundle'),
+ ('nowarning', None, 'update'),
+]
+
+def reposetup(ui, repo):
+ repo._explicitaccess = set()
+
+def _computehidden(repo):
+ hidden = repoview.filterrevs(repo, 'visible')
+ cl = repo.changelog
+ dynamic = hidden & repo._explicitaccess
+ if dynamic:
+ blocked = cl.ancestors(dynamic, inclusive=True)
+ hidden = frozenset(r for r in hidden if r not in blocked)
+ return hidden
+
+def setupdirectaccess():
+ """ Add two new filtername that behave like visible to provide direct access
+ and direct access with warning. Wraps the commands to setup direct access """
+ repoview.filtertable.update({'visible-directaccess-nowarn': _computehidden})
+ repoview.filtertable.update({'visible-directaccess-warn': _computehidden})
+ branchmap.subsettable['visible-directaccess-nowarn'] = 'visible'
+ branchmap.subsettable['visible-directaccess-warn'] = 'visible'
+
+ for warn, ext, cmd in directaccesslevel:
+ try:
+ cmdtable = extensions.find(ext).cmdtable if ext else commands.table
+ wrapper = wrapwitherror if warn == 'error' else wrapwithoutwarning
+ extensions.wrapcommand(cmdtable, cmd, wrapper)
+ except (error.UnknownCommand, KeyError):
+ pass
+
+def wrapwitherror(orig, ui, repo, *args, **kwargs):
+ if repo and repo.filtername == 'visible-directaccess-warn':
+ repo = repo.filtered('visible')
+ return orig(ui, repo, *args, **kwargs)
+
+def wrapwithoutwarning(orig, ui, repo, *args, **kwargs):
+ if repo and repo.filtername == 'visible-directaccess-warn':
+ repo = repo.filtered("visible-directaccess-nowarn")
+ return orig(ui, repo, *args, **kwargs)
+
+def uisetup(ui):
+ """ Change ordering of extensions to ensure that directaccess extsetup comes
+ after the one of the extensions in the loadsafter list """
+ loadsafter = ui.configlist('directaccess','loadsafter')
+ order = list(extensions._order)
+ directaccesidx = order.index('directaccess')
+
+ # The min idx for directaccess to load after all the extensions in loadafter
+ minidxdirectaccess = directaccesidx
+
+ for ext in loadsafter:
+ try:
+ minidxdirectaccess = max(minidxdirectaccess, order.index(ext))
+ except ValueError:
+ pass # extension not loaded
+
+ if minidxdirectaccess > directaccesidx:
+ order.insert(minidxdirectaccess + 1, 'directaccess')
+ order.remove('directaccess')
+ extensions._order = order
+
+def _repository(orig, *args, **kwargs):
+ """Make visible-directaccess-warn the default filter for new repos"""
+ repo = orig(*args, **kwargs)
+ return repo.filtered("visible-directaccess-warn")
+
+def extsetup(ui):
+ extensions.wrapfunction(revset, 'posttreebuilthook', _posttreebuilthook)
+ extensions.wrapfunction(hg, 'repository', _repository)
+ setupdirectaccess()
+
+def gethashsymbols(tree):
+ # Returns the list of symbols of the tree that look like hashes
+ # for example for the revset 3::abe3ff it will return ('abe3ff')
+ if not tree:
+ return []
+
+ if len(tree) == 2 and tree[0] == "symbol":
+ try:
+ int(tree[1])
+ return []
+ except ValueError as e:
+ return [tree[1]]
+ elif len(tree) == 3:
+ return gethashsymbols(tree[1]) + gethashsymbols(tree[2])
+ else:
+ return []
+
+def _posttreebuilthook(orig, tree, repo):
+ # This is use to enabled direct hash access
+ # We extract the symbols that look like hashes and add them to the
+ # explicitaccess set
+ orig(tree, repo)
+ filternm = ""
+ if repo is not None:
+ filternm = repo.filtername
+ if filternm is not None and filternm.startswith('visible-directaccess'):
+ prelength = len(repo._explicitaccess)
+ accessbefore = set(repo._explicitaccess)
+ repo.symbols = gethashsymbols(tree)
+ cl = repo.unfiltered().changelog
+ for node in repo.symbols:
+ try:
+ node = cl._partialmatch(node)
+ except error.LookupError:
+ node = None
+ if node is not None:
+ rev = cl.rev(node)
+ if rev not in repo.changelog:
+ repo._explicitaccess.add(rev)
+ if prelength != len(repo._explicitaccess):
+ if repo.filtername != 'visible-directaccess-nowarn':
+ unhiddencommits = repo._explicitaccess - accessbefore
+ repo.ui.warn( _("Warning: accessing hidden changesets %s "
+ "for write operation\n") %
+ (",".join([str(repo.unfiltered()[l])
+ for l in unhiddencommits])))
+ repo.invalidatevolatilesets()
--- a/hgext/evolve.py Thu Jun 25 17:22:17 2015 -0700
+++ b/hgext/evolve.py Thu Jun 25 17:37:43 2015 -0700
@@ -682,16 +682,18 @@
@eh.wrapcommand("pull")
def wrapmayobsoletewc(origfn, ui, repo, *args, **opts):
"""Warn that the working directory parent is an obsolete changeset"""
-
- prior = (repo['.'].obsolete(), repo['.'].rev)
- try:
- res = origfn(ui, repo, *args, **opts)
- finally:
- after = (repo['.'].obsolete(), repo['.'].rev)
- if prior != after and after[0]:
+ def warnobsolete():
+ if repo['.'].obsolete():
ui.warn(_('working directory parent is obsolete!\n'))
if (not ui.quiet) and obsolete.isenabled(repo, commandopt):
ui.warn(_('(use "hg evolve" to update to its successor)\n'))
+ wlock = None
+ try:
+ wlock = repo.wlock()
+ repo._afterlock(warnobsolete)
+ res = origfn(ui, repo, *args, **opts)
+ finally:
+ lockmod.release(wlock)
return res
# XXX this could wrap transaction code
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/inhibit.py Thu Jun 25 17:37:43 2015 -0700
@@ -0,0 +1,227 @@
+"""reduce the changesets evolution feature scope for early and noob friendly ui
+
+the full scale changeset evolution have some massive bleeding edge and it is
+very easy for people not very intimate with the concept to end up in intricate
+situation. in order to get some of the benefit sooner, this extension is
+disabling some of the less polished aspect of evolution. it should gradually
+get thinner and thinner as changeset evolution will get more polished. this
+extension is only recommended for large scale organisations. individual user
+should probably stick on using evolution in its current state, understand its
+concept and provide feedback
+
+This extension provides the ability to "inhibit" obsolescence markers. obsolete
+revision can be cheaply brought back to life that way.
+However as the inhibitor are not fitting in an append only model, this is
+incompatible with sharing mutable history.
+"""
+from mercurial import localrepo
+from mercurial import obsolete
+from mercurial import extensions
+from mercurial import cmdutil
+from mercurial import error
+from mercurial import scmutil
+from mercurial import commands
+from mercurial import lock as lockmod
+from mercurial import bookmarks
+from mercurial.i18n import _
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+
+def reposetup(ui, repo):
+
+ class obsinhibitedrepo(repo.__class__):
+
+ @localrepo.storecache('obsinhibit')
+ def _obsinhibit(self):
+ # XXX we should make sure it is invalidated by transaction failure
+ obsinhibit = set()
+ raw = self.sopener.tryread('obsinhibit')
+ for i in xrange(0, len(raw), 20):
+ obsinhibit.add(raw[i:i+20])
+ return obsinhibit
+
+ def commit(self, *args, **kwargs):
+ newnode = super(obsinhibitedrepo, self).commit(*args, **kwargs)
+ if newnode is not None:
+ _inhibitmarkers(repo, [newnode])
+ return newnode
+
+ repo.__class__ = obsinhibitedrepo
+
+def _update(orig, ui, repo, *args, **kwargs):
+ """
+ When moving to a commit we want to inhibit any obsolete commit affecting
+ the changeset we are updating to. In other words we don't want any visible
+ commit to be obsolete.
+ """
+ wlock = None
+ try:
+ # Evolve is running a hook on lock release to display a warning message
+ # if the workind dir's parent is obsolete.
+ # We take the lock here to make sure that we inhibit the parent before
+ # that hook get a chance to run.
+ wlock = repo.wlock()
+ res = orig(ui, repo, *args, **kwargs)
+ newhead = repo['.'].node()
+ _inhibitmarkers(repo, [newhead])
+ return res
+ finally:
+ lockmod.release(wlock)
+
+def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
+ """ Add inhibition markers to every obsolete bookmarks """
+ repo = bkmstoreinst._repo
+ bkmstorenodes = [repo[v].node() for v in bkmstoreinst.values()]
+ _inhibitmarkers(repo, bkmstorenodes)
+ return orig(bkmstoreinst, *args, **kwargs)
+
+def _bookmark(orig, ui, repo, *bookmarks, **opts):
+ """ Add a -D option to the bookmark command, map it to prune -B """
+ haspruneopt = opts.get('prune', False)
+ if not haspruneopt:
+ return orig(ui, repo, *bookmarks, **opts)
+
+ # Call prune -B
+ evolve = extensions.find('evolve')
+ optsdict = {
+ 'new': [],
+ 'succ': [],
+ 'rev': [],
+ 'bookmark': bookmarks[0],
+ 'keep': None,
+ 'biject': False,
+ }
+ evolve.cmdprune(ui, repo, **optsdict)
+
+# obsolescence inhibitor
+########################
+
+def _schedulewrite(tr, obsinhibit):
+ """Make sure on disk content will be updated on transaction commit"""
+ def writer(fp):
+ """Serialize the inhibited list to disk.
+ """
+ raw = ''.join(obsinhibit)
+ fp.write(raw)
+ tr.addfilegenerator('obsinhibit', ('obsinhibit',), writer)
+ tr.hookargs['obs_inbihited'] = '1'
+
+def _filterpublic(repo, nodes):
+ """filter out inhibitor on public changeset
+
+ Public changesets are already immune to obsolescence"""
+ getrev = repo.changelog.nodemap.get
+ getphase = repo._phasecache.phase
+ return (n for n in repo._obsinhibit
+ if getrev(n) is not None and getphase(repo, getrev(n)))
+
+def _inhibitmarkers(repo, nodes):
+ """add marker inhibitor for all obsolete revision under <nodes>
+
+ Content of <nodes> and all mutable ancestors are considered. Marker for
+ obsolete revision only are created.
+ """
+ newinhibit = repo.set('::%ln and obsolete()', nodes)
+ if newinhibit:
+ lock = tr = None
+ try:
+ lock = repo.lock()
+ tr = repo.transaction('obsinhibit')
+ repo._obsinhibit.update(c.node() for c in newinhibit)
+ _schedulewrite(tr, _filterpublic(repo, repo._obsinhibit))
+ repo.invalidatevolatilesets()
+ tr.close()
+ finally:
+ lockmod.release(tr, lock)
+
+def _deinhibitmarkers(repo, nodes):
+ """lift obsolescence inhibition on a set of nodes
+
+ This will be triggered when inhibited nodes received new obsolescence
+ markers. Otherwise the new obsolescence markers would also be inhibited.
+ """
+ deinhibited = repo._obsinhibit & set(nodes)
+ if deinhibited:
+ tr = repo.transaction('obsinhibit')
+ try:
+ repo._obsinhibit -= deinhibited
+ _schedulewrite(tr, _filterpublic(repo, repo._obsinhibit))
+ repo.invalidatevolatilesets()
+ tr.close()
+ finally:
+ tr.release()
+
+def _createmarkers(orig, repo, relations, flag=0, date=None, metadata=None):
+ """wrap markers create to make sure we de-inhibit target nodes"""
+ # wrapping transactio to unify the one in each function
+ tr = repo.transaction('add-obsolescence-marker')
+ try:
+ orig(repo, relations, flag, date, metadata)
+ precs = (r[0].node() for r in relations)
+ _deinhibitmarkers(repo, precs)
+ tr.close()
+ finally:
+ tr.release()
+
+def transactioncallback(orig, repo, *args, **kwargs):
+ """ Wrap localrepo.transaction to inhibit new obsolete changes """
+ def inhibitposttransaction(transaction):
+ # At the end of the transaction we catch all the new visible and
+ # obsolete commit to inhibit them
+ visibleobsolete = repo.revs('obsolete() - hidden()')
+ ignoreset = set(getattr(repo, '_rebaseset', []))
+ visibleobsolete = list(r for r in visibleobsolete if r not in ignoreset)
+ if visibleobsolete:
+ _inhibitmarkers(repo, [repo[r].node() for r in visibleobsolete])
+ transaction = orig(repo, *args, **kwargs)
+ transaction.addpostclose('inhibitposttransaction', inhibitposttransaction)
+ return transaction
+
+def extsetup(ui):
+ # lets wrap the computation of the obsolete set
+ # We apply inhibition there
+ obsfunc = obsolete.cachefuncs['obsolete']
+ def _computeobsoleteset(repo):
+ """remove any inhibited nodes from the obsolete set
+
+ This will trickle down to other part of mercurial (hidden, log, etc)"""
+ obs = obsfunc(repo)
+ getrev = repo.changelog.nodemap.get
+ for n in repo._obsinhibit:
+ obs.discard(getrev(n))
+ return obs
+ try:
+ extensions.find('directaccess')
+ except KeyError:
+ errormsg = _('Cannot use inhibit without the direct access extension')
+ raise error.Abort(errormsg)
+
+ # Wrapping this to inhibit obsolete revs resulting from a transaction
+ extensions.wrapfunction(localrepo.localrepository,
+ 'transaction', transactioncallback)
+
+ obsolete.cachefuncs['obsolete'] = _computeobsoleteset
+ # wrap create marker to make it able to lift the inhibition
+ extensions.wrapfunction(obsolete, 'createmarkers', _createmarkers)
+ # drop divergence computation since it is incompatible with "light revive"
+ obsolete.cachefuncs['divergent'] = lambda repo: set()
+ # drop bumped computation since it is incompatible with "light revive"
+ obsolete.cachefuncs['bumped'] = lambda repo: set()
+ # wrap update to make sure that no obsolete commit is visible after an
+ # update
+ extensions.wrapcommand(commands.table, 'update', _update)
+ # There are two ways to save bookmark changes during a transation, we
+ # wrap both to add inhibition markers.
+ extensions.wrapfunction(bookmarks.bmstore, 'recordchange', _bookmarkchanged)
+ extensions.wrapfunction(bookmarks.bmstore, 'write', _bookmarkchanged)
+ # Add bookmark -D option
+ entry = extensions.wrapcommand(commands.table, 'bookmark', _bookmark)
+ entry[1].append(('D','prune',None,
+ _('delete the bookmark and prune the commits underneath')))
+
+@command('debugobsinhibit', [], '')
+def cmddebugobsinhibit(ui, repo, *revs):
+ """inhibit obsolescence markers effect on a set of revs"""
+ nodes = (repo[r].node() for r in scmutil.revrange(repo, revs))
+ _inhibitmarkers(repo, nodes)
--- a/setup.py Thu Jun 25 17:22:17 2015 -0700
+++ b/setup.py Thu Jun 25 17:37:43 2015 -0700
@@ -19,6 +19,10 @@
'hgext.evolve',
]
+if os.environ.get('INCLUDE_INHIBIT'):
+ py_modules.append('hgext.inhibit')
+ py_modules.append('hgext.directaccess')
+
setup(
name='hg-evolve',
version=get_version('hgext/evolve.py'),
--- a/tests/test-amend.t Thu Jun 25 17:22:17 2015 -0700
+++ b/tests/test-amend.t Thu Jun 25 17:37:43 2015 -0700
@@ -155,5 +155,6 @@
-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
+ -i --interactive use interactive mode
(some details hidden, use --verbose to show complete help)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-inhibit.t Thu Jun 25 17:37:43 2015 -0700
@@ -0,0 +1,762 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [ui]
+ > logtemplate = {rev}:{node|short} {desc}\n
+ > [experimental]
+ > prunestrip=True
+ > evolution=createmarkers
+ > [extensions]
+ > rebase=
+ > strip=
+ > EOF
+ $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+ $ echo "directaccess=$(echo $(dirname $TESTDIR))/hgext/directaccess.py" >> $HGRCPATH
+ $ echo "inhibit=$(echo $(dirname $TESTDIR))/hgext/inhibit.py" >> $HGRCPATH
+ $ mkcommit() {
+ > echo "$1" > "$1"
+ > hg add "$1"
+ > hg ci -m "add $1"
+ > }
+
+ $ hg init inhibit
+ $ cd inhibit
+ $ mkcommit cA
+ $ mkcommit cB
+ $ mkcommit cC
+ $ mkcommit cD
+ $ hg up 'desc(cA)'
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ mkcommit cE
+ created new head
+ $ mkcommit cG
+ $ mkcommit cH
+ $ mkcommit cJ
+ $ hg log -G
+ @ 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 3:2db36d8066ff add cD
+ | |
+ | o 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+
+plain prune
+
+ $ hg strip 1::
+ 3 changesets pruned
+ $ hg log -G
+ @ 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg debugobsinhibit --hidden 1::
+ $ hg log -G
+ @ 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 3:2db36d8066ff add cD
+ | |
+ | o 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+ $ hg strip --hidden 1::
+ 3 changesets pruned
+ $ hg log -G
+ @ 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+
+after amend
+
+ $ echo babar > cJ
+ $ hg commit --amend
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg debugobsinhibit --hidden 18214586bf78
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+
+and no divergence
+
+ $ hg summary
+ parent: 9:55c73a90e4b4 tip
+ add cJ
+ branch: default
+ commit: (clean)
+ update: 1 new changesets, 2 branch heads (merge)
+
+check public revision got cleared
+(when adding the second inhibitor, the first one is removed because it is public)
+
+ $ wc -m .hg/store/obsinhibit | sed -e 's/^[ \t]*//'
+ 20 .hg/store/obsinhibit
+ $ hg strip 7
+ 1 changesets pruned
+ $ hg debugobsinhibit --hidden 18214586bf78
+ $ wc -m .hg/store/obsinhibit | sed -e 's/^[ \t]*//'
+ 20 .hg/store/obsinhibit
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg phase --public 7
+ $ hg strip 9
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ working directory now at cf5c4f4554ce
+ 1 changesets pruned
+ $ hg log -G
+ o 7:18214586bf78 add cJ
+ |
+ @ 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg debugobsinhibit --hidden 55c73a90e4b4
+ $ wc -m .hg/store/obsinhibit | sed -e 's/^[ \t]*//'
+ 20 .hg/store/obsinhibit
+ $ hg log -G
+ o 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ @ 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+Update should inhibit all related unstable commits
+
+ $ hg update 2 --hidden
+ 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg log -G
+ o 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | @ 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+
+ $ hg update 9
+ 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+ $ hg strip --hidden 1::
+ 3 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+
+Bookmark should inhibit all related unstable commits
+ $ hg bookmark -r 2 book1 --hidden
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 2:7df62a38b9bf add cC
+ | |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+
+Removing a bookmark with bookmark -D should prune the changes underneath
+that are not reachable from another bookmark or head
+
+ $ hg bookmark -r 1 book2
+ $ hg bookmark -D book1 --config experimental.evolution=createmarkers #--config to make sure prune is not registered as a command.
+ bookmark 'book1' deleted
+ 1 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ | o 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+ $ hg bookmark -D book2
+ bookmark 'book2' deleted
+ 1 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+Test that direct access make changesets visible
+
+ $ hg export 2db36d8066ff 02bcbc3f6e56
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Node ID 2db36d8066ff50e8be3d3e6c2da1ebc0a8381d82
+ # Parent 7df62a38b9bf9daf968de235043ba88a8ef43393
+ add cD
+
+ diff -r 7df62a38b9bf -r 2db36d8066ff cD
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/cD Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +cD
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Node ID 02bcbc3f6e56fb2928efec2c6e24472720bf5511
+ # Parent 54ccbc537fc2d6845a5d61337c1cfb80d1d2815e
+ add cB
+
+ diff -r 54ccbc537fc2 -r 02bcbc3f6e56 cB
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/cB Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +cB
+
+But only with hash
+
+ $ hg export 2db36d8066ff::
+ # HG changeset patch
+ # User test
+ # Date 0 0
+ # Thu Jan 01 00:00:00 1970 +0000
+ # Node ID 2db36d8066ff50e8be3d3e6c2da1ebc0a8381d82
+ # Parent 7df62a38b9bf9daf968de235043ba88a8ef43393
+ add cD
+
+ diff -r 7df62a38b9bf -r 2db36d8066ff cD
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/cD Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +cD
+
+ $ hg export 1 3
+ abort: filtered revision '1' (not in 'visible-directaccess-nowarn' subset)!
+ [255]
+
+
+With severals hidden sha, rebase of one hidden stack onto another one:
+ $ hg update -C 0
+ 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+ $ mkcommit cK
+ created new head
+ $ mkcommit cL
+ $ hg update -C 9
+ 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg log -G
+ o 11:53a94305e133 add cL
+ |
+ o 10:ad78ff7d621f add cK
+ |
+ | @ 9:55c73a90e4b4 add cJ
+ | |
+ | | o 7:18214586bf78 add cJ
+ | |/
+ | o 6:cf5c4f4554ce add cH
+ | |
+ | o 5:5419eb264a33 add cG
+ | |
+ | o 4:98065434e5c6 add cE
+ |/
+ o 0:54ccbc537fc2 add cA
+
+ $ hg strip --hidden 10:
+ 2 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg rebase -s 10 -d 3
+ abort: filtered revision '3' (not in 'visible-directaccess-warn' subset)!
+ [255]
+ $ hg rebase -r ad78ff7d621f -r 53a94305e133 -d 2db36d8066ff
+ Warning: accessing hidden changesets 2db36d8066ff for write operation
+ Warning: accessing hidden changesets ad78ff7d621f for write operation
+ Warning: accessing hidden changesets 53a94305e133 for write operation
+ rebasing 10:ad78ff7d621f "add cK"
+ rebasing 11:53a94305e133 "add cL"
+ $ hg log -G
+ o 13:2f7b7704d714 add cL
+ |
+ o 12:fe1634cbe235 add cK
+ |
+ | @ 9:55c73a90e4b4 add cJ
+ | |
+ | | o 7:18214586bf78 add cJ
+ | |/
+ | o 6:cf5c4f4554ce add cH
+ | |
+ | o 5:5419eb264a33 add cG
+ | |
+ | o 4:98065434e5c6 add cE
+ | |
+ o | 3:2db36d8066ff add cD
+ | |
+ o | 2:7df62a38b9bf add cC
+ | |
+ o | 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+Check that amending in the middle of a stack does not show obsolete revs
+Since we are doing operation in the middle of the stack we cannot just
+have createmarkers as we are creating instability
+
+ $ cat >> $HGRCPATH <<EOF
+ > [experimental]
+ > evolution=all
+ > EOF
+
+ $ hg strip --hidden 1::
+ 5 changesets pruned
+ $ hg log -G
+ @ 9:55c73a90e4b4 add cJ
+ |
+ | o 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg up 7
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mkcommit cL
+ $ mkcommit cM
+ $ mkcommit cN
+ $ hg log -G
+ @ 16:a438c045eb37 add cN
+ |
+ o 15:2d66e189f5b5 add cM
+ |
+ o 14:d66ccb8c5871 add cL
+ |
+ | o 9:55c73a90e4b4 add cJ
+ | |
+ o | 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg up 15
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo "mmm" >> cM
+ $ hg amend
+ $ hg log -G
+ @ 18:210589181b14 add cM
+ |
+ | o 16:a438c045eb37 add cN
+ | |
+ | o 15:2d66e189f5b5 add cM
+ |/
+ o 14:d66ccb8c5871 add cL
+ |
+ | o 9:55c73a90e4b4 add cJ
+ | |
+ o | 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+Check that rebasing a commit twice makes the commit visible again
+
+ $ hg rebase -d 18 -r 16 --keep
+ rebasing 16:a438c045eb37 "add cN"
+ $ hg log -r 14:: -G
+ o 19:104eed5354c7 add cN
+ |
+ @ 18:210589181b14 add cM
+ |
+ | o 16:a438c045eb37 add cN
+ | |
+ | o 15:2d66e189f5b5 add cM
+ |/
+ o 14:d66ccb8c5871 add cL
+ |
+ $ hg strip -r 104eed5354c7
+ 1 changesets pruned
+ $ hg rebase -d 18 -r 16 --keep
+ rebasing 16:a438c045eb37 "add cN"
+ $ hg log -r 14:: -G
+ o 19:104eed5354c7 add cN
+ |
+ @ 18:210589181b14 add cM
+ |
+ | o 16:a438c045eb37 add cN
+ | |
+ | o 15:2d66e189f5b5 add cM
+ |/
+ o 14:d66ccb8c5871 add cL
+ |
+
+Test prunestrip
+
+ $ hg book foo -r 104eed5354c7
+ $ hg strip -r 210589181b14
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ working directory now at d66ccb8c5871
+ 2 changesets pruned
+ $ hg log -r 14:: -G -T '{rev}:{node|short} {desc|firstline} {bookmarks}\n'
+ o 16:a438c045eb37 add cN
+ |
+ o 15:2d66e189f5b5 add cM
+ |
+ @ 14:d66ccb8c5871 add cL foo
+ |
+
+Check that --hidden used with inhibit does not hide every obsolete commit
+We show the log before and after a log -G --hidden, they should be the same
+ $ hg log -G
+ o 16:a438c045eb37 add cN
+ |
+ o 15:2d66e189f5b5 add cM
+ |
+ @ 14:d66ccb8c5871 add cL
+ |
+ | o 9:55c73a90e4b4 add cJ
+ | |
+ o | 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ hg log -G --hidden
+ x 19:104eed5354c7 add cN
+ |
+ x 18:210589181b14 add cM
+ |
+ | x 17:b3c3274523f9 temporary amend commit for 2d66e189f5b5
+ | |
+ | | o 16:a438c045eb37 add cN
+ | |/
+ | o 15:2d66e189f5b5 add cM
+ |/
+ @ 14:d66ccb8c5871 add cL
+ |
+ | x 13:2f7b7704d714 add cL
+ | |
+ | x 12:fe1634cbe235 add cK
+ | |
+ | | x 11:53a94305e133 add cL
+ | | |
+ | | x 10:ad78ff7d621f add cK
+ | | |
+ | | | o 9:55c73a90e4b4 add cJ
+ | | | |
+ +-------x 8:e84f73d9ad36 temporary amend commit for 18214586bf78
+ | | | |
+ o-----+ 7:18214586bf78 add cJ
+ / / /
+ | | o 6:cf5c4f4554ce add cH
+ | | |
+ | | o 5:5419eb264a33 add cG
+ | | |
+ | | o 4:98065434e5c6 add cE
+ | |/
+ x | 3:2db36d8066ff add cD
+ | |
+ x | 2:7df62a38b9bf add cC
+ | |
+ x | 1:02bcbc3f6e56 add cB
+ |/
+ o 0:54ccbc537fc2 add cA
+
+
+ $ hg log -G
+ o 16:a438c045eb37 add cN
+ |
+ o 15:2d66e189f5b5 add cM
+ |
+ @ 14:d66ccb8c5871 add cL
+ |
+ | o 9:55c73a90e4b4 add cJ
+ | |
+ o | 7:18214586bf78 add cJ
+ |/
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+
+check that pruning and inhibited node does not confuse anything
+
+ $ hg up --hidden 210589181b14
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg strip --bundle 210589181b14
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ saved backup bundle to $TESTTMP/inhibit/.hg/strip-backup/210589181b14-e09c7b88-backup.hg (glob)
+ $ hg unbundle .hg/strip-backup/210589181b14-e09c7b88-backup.hg # restore state
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 1 changes to 2 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ Only allow direct access and check that evolve works like before
+(also disable evolve commands to avoid hint about using evolve)
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > inhibit=!
+ > [experimental]
+ > evolution=createmarkers
+ > EOF
+
+ $ hg up 15
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ working directory parent is obsolete!
+ $ cat >> $HGRCPATH <<EOF
+ > [experimental]
+ > evolution=all
+ > EOF
+ $ echo "CM" > cM
+ $ hg amend
+ $ hg log -G
+ @ 21:721c3c279519 add cM
+ |
+ | o 16:a438c045eb37 add cN
+ | |
+ | x 15:2d66e189f5b5 add cM
+ |/
+ o 14:d66ccb8c5871 add cL
+ |
+ o 7:18214586bf78 add cJ
+ |
+ o 6:cf5c4f4554ce add cH
+ |
+ o 5:5419eb264a33 add cG
+ |
+ o 4:98065434e5c6 add cE
+ |
+ o 0:54ccbc537fc2 add cA
+
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > EOF
+ $ echo "inhibit=$(echo $(dirname $TESTDIR))/hgext/inhibit.py" >> $HGRCPATH
+
+Empty commit
+ $ hg amend
+ nothing changed
+ [1]
+
+Directaccess should load after some extensions precised in the conf
+With no extension specified:
+
+ $ cat >$TESTTMP/test_extension.py << EOF
+ > from mercurial import extensions
+ > def uisetup(ui):
+ > print extensions._order
+ > EOF
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > testextension=$TESTTMP/test_extension.py
+ > EOF
+ $ hg id
+ ['rebase', 'strip', 'evolve', 'directaccess', 'inhibit', 'testextension']
+ 721c3c279519 tip
+
+With test_extension specified:
+ $ cat >> $HGRCPATH << EOF
+ > [directaccess]
+ > loadsafter=testextension
+ > EOF
+ $ hg id
+ ['rebase', 'strip', 'evolve', 'inhibit', 'testextension', 'directaccess']
+ 721c3c279519 tip
+
+Inhibit should not work without directaccess
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > directaccess=!
+ > testextension=!
+ > EOF
+ $ hg up 15
+ abort: Cannot use inhibit without the direct access extension
+ [255]
+ $ echo "directaccess=$(echo $(dirname $TESTDIR))/hgext/directaccess.py" >> $HGRCPATH
+ $ cd ..
+
+
+hg push should not allow directaccess unless forced with --hidden
+We copy the inhibhit repo to inhibit2 and make some changes to push to inhibit
+
+ $ cp -r inhibit inhibit2
+ $ pwd=$(pwd)
+ $ cd inhibit
+ $ mkcommit pk
+ $ hg id
+ 003a4735afde tip
+ $ echo "OO" > pk
+ $ hg amend
+ $ hg id
+ 71eb4f100663 tip
+
+Hidden commits cannot be pushed without --hidden
+ $ hg push -r 003a4735afde file://$pwd/inhibit2
+ pushing to file://$TESTTMP/inhibit2
+ abort: hidden revision '003a4735afde'!
+ (use --hidden to access hidden revisions)
+ [255]
+
+Visible commits can still be pushed
+ $ hg push -r 71eb4f100663 file://$pwd/inhibit2
+ pushing to file://$TESTTMP/inhibit2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ pushing 33 obsolescence markers (*) (glob)
+ 2 obsolescence markers added
--- a/tests/test-obsolete.t Thu Jun 25 17:22:17 2015 -0700
+++ b/tests/test-obsolete.t Thu Jun 25 17:37:43 2015 -0700
@@ -130,6 +130,8 @@
date: Thu Jan 01 00:00:00 1970 +0000
summary: add obsol_c
+ working directory parent is obsolete!
+ (use "hg evolve" to update to its successor)
$ mkcommit d # 5 (on 3)
1 new unstable changesets
$ qlog -r 'obsolete()'
--- a/tests/test-tutorial.t Thu Jun 25 17:22:17 2015 -0700
+++ b/tests/test-tutorial.t Thu Jun 25 17:37:43 2015 -0700
@@ -745,16 +745,20 @@
$ cd ../remote
$ hg pull local # we up again to trigger the warning. it was displayed during the push
- pulling from $TESTTMP/local
+ pulling from $TESTTMP/local (glob)
searching for changes
no changes found
pull obsolescence markers
0 obsolescence markers added
+ working directory parent is obsolete!
+ (use "hg evolve" to update to its successor)
now let's see where we are, and update to the successor
$ hg parents
bf1b0d202029 (draft): animals
+ working directory parent is obsolete!
+ (use "hg evolve" to update to its successor)
$ hg evolve
update:[8] animals
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-wireproto.t Thu Jun 25 17:22:17 2015 -0700
+++ b/tests/test-wireproto.t Thu Jun 25 17:37:43 2015 -0700
@@ -72,6 +72,7 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files (+1 heads)
+ remote: obsmarker-exchange: 139 bytes received
remote: 2 new obsolescence markers
$ hg push
pushing to ssh://user@dummy/server
@@ -89,6 +90,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
+ obsmarker-exchange: 139 bytes received
2 new obsolescence markers
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg -R ../other pull
@@ -111,6 +113,7 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
+ remote: obsmarker-exchange: 139 bytes received
remote: 2 new obsolescence markers
$ hg -R ../other pull
pulling from ssh://user@dummy/server
@@ -119,6 +122,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
+ obsmarker-exchange: 139 bytes received
2 new obsolescence markers
(run 'hg update' to get a working copy)
@@ -132,6 +136,7 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 0 changes to 1 files (+1 heads)
+ remote: obsmarker-exchange: 208 bytes received
remote: 1 new obsolescence markers
$ hg -R ../other pull
pulling from ssh://user@dummy/server
@@ -140,6 +145,7 @@
adding manifests
adding file changes
added 1 changesets with 0 changes to 3 files (+1 heads)
+ obsmarker-exchange: 208 bytes received
1 new obsolescence markers
(run 'hg heads' to see heads, 'hg merge' to merge)