# HG changeset patch # User Boris Feld # Date 2018-01-05 08:12:08 # Node ID 265cd9e19d26dd7f684f660b6c267b45427284e8 # Parent 3e3f4c03876bd1f17964536bb8074d4dd8b98ee6 visibility: improve the message when accessing filtered obsolete rev When trying to access filtered revision, it is likely because they have been obsoleted by an obs-marker. The current message shows how to access the revision anyway: abort: hidden revision '13bedc178fce'! But in the case of an obsoleted revision, the user is likely to want to update to or use the successor of the revision. We update the message to display more information about the obsolescence fate of the revision in the following cases: abort: hidden revision '13bedc178fce' is pruned! abort: hidden revision '13bedc178fce' has diverged! abort: hidden revision '13bedc178fce' was rewritten as X, Y and 2 more! Differential Revision: https://phab.mercurial-scm.org/D1591 diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -36,6 +36,7 @@ from . import ( match as matchmod, mdiff, obsolete as obsmod, + obsutil, patch, pathutil, phases, @@ -433,8 +434,21 @@ def _filterederror(repo, changeid): This is extracted in a function to help extensions (eg: evolve) to experiment with various message variants.""" if repo.filtername.startswith('visible'): - msg = _("hidden revision '%s'") % changeid + + # Check if the changeset is obsolete + unfilteredrepo = repo.unfiltered() + ctx = unfilteredrepo[changeid] + + # If the changeset is obsolete, enrich the hint with the reason that + # made this changeset not visible + if ctx.obsolete(): + reason = obsutil._getfilteredreason(unfilteredrepo, ctx) + msg = _("hidden revision '%s' %s") % (changeid, reason) + else: + msg = _("hidden revision '%s'") % changeid + hint = _('use --hidden to access hidden revisions') + return error.FilteredRepoLookupError(msg, hint=hint) msg = _("filtered revision '%s' (not in '%s' subset)") msg %= (changeid, repo.filtername) diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py --- a/mercurial/obsutil.py +++ b/mercurial/obsutil.py @@ -9,9 +9,11 @@ from __future__ import absolute_import import re +from .i18n import _ from . import ( + node as nodemod, phases, - util + util, ) class marker(object): @@ -751,6 +753,32 @@ def successorsandmarkers(repo, ctx): return values +def _getobsfate(successorssets): + """ Compute a changeset obsolescence fate based on its successorssets. + Successors can be the tipmost ones or the immediate ones. This function + return values are not meant to be shown directly to users, it is meant to + be used by internal functions only. + Returns one fate from the following values: + - pruned + - diverged + - superseded + - superseded_split + """ + + if len(successorssets) == 0: + # The commit has been pruned + return 'pruned' + elif len(successorssets) > 1: + return 'diverged' + else: + # No divergence, only one set of successors + successors = successorssets[0] + + if len(successors) == 1: + return 'superseded' + else: + return 'superseded_split' + def obsfateverb(successorset, markers): """ Return the verb summarizing the successorset and potentially using information from the markers @@ -836,3 +864,34 @@ def obsfateprinter(successors, markers, line.append(" (between %s and %s)" % (fmtmin_date, fmtmax_date)) return "".join(line) + +def _getfilteredreason(unfilteredrepo, ctx): + """return a human-friendly string on why a obsolete changeset is hidden + """ + successors = successorssets(unfilteredrepo, ctx.node()) + fate = _getobsfate(successors) + + # Be more precise in case the revision is superseded + if fate == 'pruned': + reason = _('is pruned') + elif fate == 'diverged': + reason = _('has diverged') + elif fate == 'superseded': + reason = _("was rewritten as: %s") % nodemod.short(successors[0][0]) + elif fate == 'superseded_split': + + succs = [] + for node_id in successors[0]: + succs.append(nodemod.short(node_id)) + + if len(succs) <= 2: + reason = _("was split as: %s") % ", ".join(succs) + else: + firstsuccessors = ", ".join(succs[:2]) + remainingnumber = len(succs) - 2 + + args = (firstsuccessors, remainingnumber) + successorsmsg = _("%s and %d more") % args + reason = _("was split as: %s") % successorsmsg + + return reason diff --git a/tests/test-directaccess.t b/tests/test-directaccess.t --- a/tests/test-directaccess.t +++ b/tests/test-directaccess.t @@ -40,7 +40,7 @@ Testing read only commands on the hidden Testing with rev number $ hg exp 2 --config experimental.directaccess.revnums=False - abort: hidden revision '2'! + abort: hidden revision '2' was rewritten as: 2443a0e66469! (use --hidden to access hidden revisions) [255] @@ -73,7 +73,7 @@ Testing with rev number A c $ hg status --change 2 --config experimental.directaccess.revnums=False - abort: hidden revision '2'! + abort: hidden revision '2' was rewritten as: 2443a0e66469! (use --hidden to access hidden revisions) [255] @@ -178,11 +178,11 @@ This should not throw error Commands with undefined cmdtype should not work right now $ hg phase -r 28ad74 - abort: hidden revision '28ad74'! + abort: hidden revision '28ad74' was rewritten as: 2443a0e66469! (use --hidden to access hidden revisions) [255] $ hg phase -r 2 - abort: hidden revision '2'! + abort: hidden revision '2' was rewritten as: 2443a0e66469! (use --hidden to access hidden revisions) [255] diff --git a/tests/test-log.t b/tests/test-log.t --- a/tests/test-log.t +++ b/tests/test-log.t @@ -1827,7 +1827,7 @@ enable obsolete to test hidden feature 1:a765632148dc55d38c35c4f247c618701886cb2f 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05 $ hg log -r a - abort: hidden revision 'a'! + abort: hidden revision 'a' is pruned! (use --hidden to access hidden revisions) [255] @@ -1885,7 +1885,7 @@ test hidden revision 0 (issue5385) 2:94375ec45bddd2a824535fc04855bd058c926ec0 3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e $ hg log -T'{rev}:{node}\n' -r:0 - abort: hidden revision '0'! + abort: hidden revision '0' is pruned! (use --hidden to access hidden revisions) [255] $ hg log -T'{rev}:{node}\n' -f diff --git a/tests/test-obshistory.t b/tests/test-obshistory.t new file mode 100644 --- /dev/null +++ b/tests/test-obshistory.t @@ -0,0 +1,551 @@ +This test file test the various messages when accessing obsolete +revisions. + +Global setup +============ + + $ . $TESTDIR/testlib/obsmarker-common.sh + $ cat >> $HGRCPATH < [ui] + > interactive = true + > [phases] + > publish=False + > [experimental] + > evolution.createmarkers = yes + > evolution.effect-flags = yes + > EOF + +Test output on amended commit +============================= + +Test setup +---------- + + $ hg init $TESTTMP/local-amend + $ cd $TESTTMP/local-amend + $ mkcommit ROOT + $ mkcommit A0 + $ echo 42 >> A0 + $ hg commit --amend -m "A1 + > + > Better commit message" + $ hg log --hidden -G + @ changeset: 2:4ae3a4151de9 + | tag: tip + | parent: 0:ea207398892e + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A1 + | + | x changeset: 1:471f378eab4c + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: rewritten using amend as 2:4ae3a4151de9 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + +Actual test +----------- + $ hg update 471f378eab4c + abort: hidden revision '471f378eab4c' was rewritten as: 4ae3a4151de9! + (use --hidden to access hidden revisions) + [255] + $ hg update --hidden "desc(A0)" + updating to a hidden changeset 471f378eab4c + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Test output with pruned commit +============================== + +Test setup +---------- + + $ hg init $TESTTMP/local-prune + $ cd $TESTTMP/local-prune + $ mkcommit ROOT + $ mkcommit A0 # 0 + $ mkcommit B0 # 1 + $ hg log --hidden -G + @ changeset: 2:0dec01379d3b + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: B0 + | + o changeset: 1:471f378eab4c + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + + $ hg debugobsolete --record-parents `getid 'desc(B0)'` + obsoleted 1 changesets + + $ hg log --hidden -G + @ changeset: 2:0dec01379d3b + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: pruned + | summary: B0 + | + o changeset: 1:471f378eab4c + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + + +Actual test +----------- + $ hg up 1 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg up 0dec01379d3b + abort: hidden revision '0dec01379d3b' is pruned! + (use --hidden to access hidden revisions) + [255] + $ hg up --hidden -r 'desc(B0)' + updating to a hidden changeset 0dec01379d3b + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Test output with splitted commit +================================ + +Test setup +---------- + + $ hg init $TESTTMP/local-split + $ cd $TESTTMP/local-split + $ mkcommit ROOT + $ echo 42 >> a + $ echo 43 >> b + $ hg commit -A -m "A0" + adding a + adding b + $ hg log --hidden -G + @ changeset: 1:471597cad322 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + +# Simulate a split + $ hg up 0 + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + + $ echo 42 >> a + $ hg commit -A -m "A0" + adding a + created new head + + $ echo 43 >> b + $ hg commit -A -m "A0" + adding b + + $ hg debugobsolete `getid '1'` `getid '2'` `getid '3'` + obsoleted 1 changesets + + $ hg log --hidden -G + @ changeset: 3:f257fde29c7a + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 2:337fec4d2edc + | parent: 0:ea207398892e + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + | x changeset: 1:471597cad322 + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: split as 2:337fec4d2edc, 3:f257fde29c7a + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + +Actual test +----------- + $ hg update 471597cad322 + abort: hidden revision '471597cad322' was split as: 337fec4d2edc, f257fde29c7a! + (use --hidden to access hidden revisions) + [255] + $ hg update --hidden 'min(desc(A0))' + updating to a hidden changeset 471597cad322 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Test output with lots of splitted commit +======================================== + +Test setup +---------- + + $ hg init $TESTTMP/local-lots-split + $ cd $TESTTMP/local-lots-split + $ mkcommit ROOT + $ echo 42 >> a + $ echo 43 >> b + $ echo 44 >> c + $ echo 45 >> d + $ hg commit -A -m "A0" + adding a + adding b + adding c + adding d + $ hg log --hidden -G + @ changeset: 1:de7290d8b885 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + +# Simulate a split + $ hg up 0 + 0 files updated, 0 files merged, 4 files removed, 0 files unresolved + + $ echo 42 >> a + $ hg commit -A -m "A0" + adding a + created new head + + $ echo 43 >> b + $ hg commit -A -m "A0" + adding b + + $ echo 44 >> c + $ hg commit -A -m "A0" + adding c + + $ echo 45 >> d + $ hg commit -A -m "A0" + adding d + + $ hg debugobsolete `getid '1'` `getid '2'` `getid '3'` `getid '4'` `getid '5'` + obsoleted 1 changesets + + $ hg log --hidden -G + @ changeset: 5:c7f044602e9b + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 4:1ae8bc733a14 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 3:f257fde29c7a + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 2:337fec4d2edc + | parent: 0:ea207398892e + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + | x changeset: 1:de7290d8b885 + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: split as 2:337fec4d2edc, 3:f257fde29c7a, 4:1ae8bc733a14, 5:c7f044602e9b + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + +Actual test +----------- + $ hg update de7290d8b885 + abort: hidden revision 'de7290d8b885' was split as: 337fec4d2edc, f257fde29c7a and 2 more! + (use --hidden to access hidden revisions) + [255] + $ hg update --hidden 'min(desc(A0))' + updating to a hidden changeset de7290d8b885 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Test output with folded commit +============================== + +Test setup +---------- + + $ hg init $TESTTMP/local-fold + $ cd $TESTTMP/local-fold + $ mkcommit ROOT + $ mkcommit A0 + $ mkcommit B0 + $ hg log --hidden -G + @ changeset: 2:0dec01379d3b + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: B0 + | + o changeset: 1:471f378eab4c + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + +# Simulate a fold + $ hg up 0 + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ echo "A0" > A0 + $ echo "B0" > B0 + $ hg add A0 B0 + $ hg commit -m "C0" + created new head + + $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(C0)'` + obsoleted 1 changesets + $ hg debugobsolete `getid 'desc(B0)'` `getid 'desc(C0)'` + obsoleted 1 changesets + + $ hg log --hidden -G + @ changeset: 3:eb5a0daa2192 + | tag: tip + | parent: 0:ea207398892e + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: C0 + | + | x changeset: 2:0dec01379d3b + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | obsolete: rewritten as 3:eb5a0daa2192 + | | summary: B0 + | | + | x changeset: 1:471f378eab4c + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: rewritten as 3:eb5a0daa2192 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + + Actual test + ----------- + $ hg update 471f378eab4c + abort: hidden revision '471f378eab4c' was rewritten as: eb5a0daa2192! + (use --hidden to access hidden revisions) + [255] + $ hg update --hidden 'desc(A0)' + updating to a hidden changeset 471f378eab4c + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg update 0dec01379d3b + abort: hidden revision '0dec01379d3b' was rewritten as: eb5a0daa2192! + (use --hidden to access hidden revisions) + [255] + $ hg update --hidden 'desc(B0)' + updating to a hidden changeset 0dec01379d3b + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Test output with divergence +=========================== + +Test setup +---------- + + $ hg init $TESTTMP/local-divergence + $ cd $TESTTMP/local-divergence + $ mkcommit ROOT + $ mkcommit A0 + $ hg commit --amend -m "A1" + $ hg log --hidden -G + @ changeset: 2:fdf9bde5129a + | tag: tip + | parent: 0:ea207398892e + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A1 + | + | x changeset: 1:471f378eab4c + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: rewritten using amend as 2:fdf9bde5129a + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + + $ hg update --hidden 'desc(A0)' + updating to a hidden changeset 471f378eab4c + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg commit --amend -m "A2" + $ hg log --hidden -G + @ changeset: 3:65b757b745b9 + | tag: tip + | parent: 0:ea207398892e + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | instability: content-divergent + | summary: A2 + | + | * changeset: 2:fdf9bde5129a + |/ parent: 0:ea207398892e + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | instability: content-divergent + | summary: A1 + | + | x changeset: 1:471f378eab4c + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: rewritten using amend as 2:fdf9bde5129a + | obsolete: rewritten using amend as 3:65b757b745b9 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + +Actual test +----------- + $ hg update 471f378eab4c + abort: hidden revision '471f378eab4c' has diverged! + (use --hidden to access hidden revisions) + [255] + $ hg update --hidden 'desc(A0)' + updating to a hidden changeset 471f378eab4c + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Test output with amended + folded commit +======================================== + +Test setup +---------- + + $ hg init $TESTTMP/local-amend-fold + $ cd $TESTTMP/local-amend-fold + $ mkcommit ROOT + $ mkcommit A0 + $ mkcommit B0 + $ hg commit --amend -m "B1" + $ hg log --hidden -G + @ changeset: 3:b7ea6d14e664 + | tag: tip + | parent: 1:471f378eab4c + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: B1 + | + | x changeset: 2:0dec01379d3b + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: rewritten using amend as 3:b7ea6d14e664 + | summary: B0 + | + o changeset: 1:471f378eab4c + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + + +# Simulate a fold + $ hg up 0 + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ echo "A0" > A0 + $ echo "B0" > B0 + $ hg add A0 B0 + $ hg commit -m "C0" + created new head + + $ hg debugobsolete `getid 'desc(A0)'` `getid 'desc(C0)'` + obsoleted 1 changesets + $ hg debugobsolete `getid 'desc(B1)'` `getid 'desc(C0)'` + obsoleted 1 changesets + + $ hg log --hidden -G + @ changeset: 4:eb5a0daa2192 + | tag: tip + | parent: 0:ea207398892e + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: C0 + | + | x changeset: 3:b7ea6d14e664 + | | parent: 1:471f378eab4c + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | obsolete: rewritten as 4:eb5a0daa2192 + | | summary: B1 + | | + | | x changeset: 2:0dec01379d3b + | |/ user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | obsolete: rewritten using amend as 3:b7ea6d14e664 + | | summary: B0 + | | + | x changeset: 1:471f378eab4c + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: rewritten as 4:eb5a0daa2192 + | summary: A0 + | + o changeset: 0:ea207398892e + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: ROOT + + Actual test + ----------- + $ hg update 471f378eab4c + abort: hidden revision '471f378eab4c' was rewritten as: eb5a0daa2192! + (use --hidden to access hidden revisions) + [255] + $ hg update --hidden 'desc(A0)' + updating to a hidden changeset 471f378eab4c + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg update --hidden 0dec01379d3b + updating to a hidden changeset 0dec01379d3b + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg update 0dec01379d3b + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg update --hidden 'desc(B0)' + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t --- a/tests/test-obsolete.t +++ b/tests/test-obsolete.t @@ -197,7 +197,7 @@ check that various commands work well wi abort: unknown revision '6'! [255] $ hg log -r 4 - abort: hidden revision '4'! + abort: hidden revision '4' was rewritten as: 5601fb93a350! (use --hidden to access hidden revisions) [255] $ hg debugrevspec 'rev(6)' @@ -1337,7 +1337,7 @@ bookmarks change 4:13bedc178fce (draft *obsolete*) [ bookb] add b [rewritten using amend as 5:a9b1f8652753] $ hg book -d bookb $ hg log -r 13bedc178fce - abort: hidden revision '13bedc178fce'! + abort: hidden revision '13bedc178fce' was rewritten as: a9b1f8652753! (use --hidden to access hidden revisions) [255]