D1591: visibility: improve the message when accessing filtered obsolete rev

lothiraldan (Boris Feld) phabricator at mercurial-scm.org
Tue Dec 5 14:11:22 UTC 2017


lothiraldan created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  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:
  
    (use --hidden to access hidden revisions)
  
  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 in these cases:
  
    (use --hidden to access hidden revisions; pruned)
    
    (use --hidden to access hidden revisions; successor: 4ae3a4151de9)
    
    (use --hidden to access hidden revisions; diverged)

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1591

AFFECTED FILES
  mercurial/context.py
  mercurial/obsutil.py
  tests/test-log.t
  tests/test-obshistory.t
  tests/test-obsolete.t

CHANGE DETAILS

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 @@
   [255]
   $ hg log -r 4
   abort: hidden revision '4'!
-  (use --hidden to access hidden revisions)
+  (use --hidden to access hidden revisions; successor: 5601fb93a350)
   [255]
   $ hg debugrevspec 'rev(6)'
   $ hg debugrevspec 'rev(4)'
@@ -1325,7 +1325,7 @@
   $ hg book -d bookb
   $ hg log -r 13bedc178fce
   abort: hidden revision '13bedc178fce'!
-  (use --hidden to access hidden revisions)
+  (use --hidden to access hidden revisions; successor: a9b1f8652753)
   [255]
 
 Empty out the test extension, as it isn't compatible with later parts
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,541 @@
+This test file test the various messages when accessing obsolete
+revisions.
+
+Global setup
+============
+
+  $ . $TESTDIR/testlib/obsmarker-common.sh
+  $ cat >> $HGRCPATH <<EOF
+  > [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'!
+  (use --hidden to access hidden revisions; successor: 4ae3a4151de9)
+  [255]
+  $ hg update --hidden "desc(A0)"
+  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'!
+  (use --hidden to access hidden revisions; pruned)
+  [255]
+  $ hg up --hidden -r 'desc(B0)'
+  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'!
+  (use --hidden to access hidden revisions; successors: 337fec4d2edc, f257fde29c7a)
+  [255]
+  $ hg update --hidden 'min(desc(A0))'
+  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'!
+  (use --hidden to access hidden revisions; successors: 337fec4d2edc, f257fde29c7a and 2 more)
+  [255]
+  $ hg update --hidden 'min(desc(A0))'
+  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'!
+  (use --hidden to access hidden revisions; successor: eb5a0daa2192)
+  [255]
+  $ hg update --hidden 'desc(A0)'
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg update 0dec01379d3b
+  abort: hidden revision '0dec01379d3b'!
+  (use --hidden to access hidden revisions; successor: eb5a0daa2192)
+  [255]
+  $ hg update --hidden 'desc(B0)'
+  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)'
+  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
+  |
+  | o  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'!
+  (use --hidden to access hidden revisions; diverged)
+  [255]
+  $ hg update --hidden 'desc(A0)'
+  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'!
+  (use --hidden to access hidden revisions; successor: eb5a0daa2192)
+  [255]
+  $ hg update --hidden 'desc(A0)'
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg update --hidden 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-log.t b/tests/test-log.t
--- a/tests/test-log.t
+++ b/tests/test-log.t
@@ -1718,7 +1718,7 @@
   0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
   $ hg log -r a
   abort: hidden revision 'a'!
-  (use --hidden to access hidden revisions)
+  (use --hidden to access hidden revisions; pruned)
   [255]
 
 test that parent prevent a changeset to be hidden
@@ -1775,7 +1775,7 @@
   3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
   $ hg log -T'{rev}:{node}\n' -r:0
   abort: hidden revision '0'!
-  (use --hidden to access hidden revisions)
+  (use --hidden to access hidden revisions; pruned)
   [255]
   $ hg log -T'{rev}:{node}\n' -f
   3:d7d28b288a6b83d5d2cf49f10c5974deed3a1d2e
diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py
--- a/mercurial/obsutil.py
+++ b/mercurial/obsutil.py
@@ -751,6 +751,32 @@
 
     return values
 
+def _getobsfate(successorssets):
+    """ Compute a changeset obsolescence fate based on his 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 in the following list:
+    - pruned
+    - diverged
+    - superseed
+    - superseed_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 'superseed'
+        else:
+            return 'superseed_split'
+
 def obsfateverb(successorset, markers):
     """ Return the verb summarizing the successorset and potentially using
     information from the markers
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -35,7 +35,9 @@
     fileset,
     match as matchmod,
     mdiff,
+    node as nodemod,
     obsolete as obsmod,
+    obsutil,
     patch,
     pathutil,
     phases,
@@ -434,12 +436,49 @@
     experiment with various message variants."""
     if repo.filtername.startswith('visible'):
         msg = _("hidden revision '%s'") % changeid
-        hint = _('use --hidden to access hidden revisions')
+
+        # 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 = _getobsoletereason(ctx, unfilteredrepo)
+            hint = _('use --hidden to access hidden revisions; %s') % reason
+        else:
+            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)
     return error.FilteredRepoLookupError(msg)
 
+def _getobsoletereason(ctx, unfilteredrepo):
+    successors = obsutil.successorssets(unfilteredrepo, ctx.node())
+    reason = obsutil._getobsfate(successors)
+
+    # Be more precise in case the revision is superseed
+    if reason == 'superseed':
+        reason = _("successor: %s") % nodemod.short(successors[0][0])
+    elif reason == 'superseed_split':
+
+        succs = []
+        for node_id in successors[0]:
+            succs.append(nodemod.short(node_id))
+
+        if len(succs) <= 2:
+            reason = _("successors: %s") % ", ".join(succs)
+        else:
+            firstsuccessors = ", ".join(succs[:2])
+            remainingnumber = len(succs) - 2
+
+            args = (firstsuccessors, remainingnumber)
+            successorsmsg = _("%s and %d more") % args
+            reason = _("successors: %s") % successorsmsg
+
+    return reason
+
 class changectx(basectx):
     """A changecontext object makes access to data related to a particular
     changeset convenient. It represents a read-only context already present in



To: lothiraldan, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list