followlines: join merge parents line ranges in blockdescendants() (issue5595)
authorDenis Laxalde <denis.laxalde@logilab.fr>
Wed, 05 Jul 2017 13:54:53 +0200
changeset 33284 b2670290eab4
parent 33283 634b259079c5
child 33285 98f6c25aaf61
followlines: join merge parents line ranges in blockdescendants() (issue5595) In blockdescendants(), we had an assertion when line range of a merge changeset was not consistent depending on which parent was considered for computation. For instance, this might occur when file content (in lookup range) is significantly different between parent branches of the merge as demonstrated in added tests (where we almost completely rewrite the "baz" file while also introducing similarities with its content in the other branch we later merge to). Now, in such case, we combine line ranges from all parents by storing the envelope of both line ranges. This is conservative (the line range is extended, possibly unnecessarily) but at least this should avoid missing descendants with changes in a range that would fall in that of one parent but not in another one (the case of "baz: narrow change (2->2+)" changeset in tests).
mercurial/dagop.py
tests/test-annotate.t
--- a/mercurial/dagop.py	Tue Jul 04 22:35:52 2017 -0700
+++ b/mercurial/dagop.py	Wed Jul 05 13:54:53 2017 +0200
@@ -287,12 +287,13 @@
                 continue
             inrangep, linerange1 = _changesrange(c, p, linerange2, diffopts)
             inrange = inrange or inrangep
-            # If revision 'i' has been seen (it's a merge), we assume that its
-            # line range is the same independently of which parents was used
-            # to compute it.
-            assert i not in seen or seen[i][1] == linerange1, (
-                'computed line range for %s is not consistent between '
-                'ancestor branches' % c)
+            # If revision 'i' has been seen (it's a merge) and the line range
+            # previously computed differs from the one we just got, we take the
+            # surrounding interval. This is conservative but avoids loosing
+            # information.
+            if i in seen and seen[i][1] != linerange1:
+                lbs, ubs = zip(linerange1, seen[i][1])
+                linerange1 = min(lbs), max(ubs)
             seen[i] = c, linerange1
         if inrange:
             yield c, linerange1
--- a/tests/test-annotate.t	Tue Jul 04 22:35:52 2017 -0700
+++ b/tests/test-annotate.t	Wed Jul 05 13:54:53 2017 +0200
@@ -725,6 +725,65 @@
   |
   ~
 
+Issue5595: on a merge changeset with different line ranges depending on
+parent, be conservative and use the surrounding interval to avoid loosing
+track of possible further descendants in specified range.
+
+  $ hg up 23 --quiet
+  $ hg cat baz -r 24
+  0
+  0
+  1 baz:1
+  2 baz:2
+  3+ baz:3
+  4 baz:4
+  5
+  6
+  $ cat > baz << EOF
+  > 0
+  > 0
+  > a
+  > b
+  > 3+ baz:3
+  > 4 baz:4
+  > y
+  > z
+  > EOF
+  $ hg ci -m 'baz: mostly rewrite with some content from 24'
+  created new head
+  $ hg merge --tool :merge-other 24
+  merging baz
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg ci -m 'merge forgetting about baz rewrite'
+  $ cat > baz << EOF
+  > 0
+  > 0
+  > 1 baz:1
+  > 2+ baz:2
+  > 3+ baz:3
+  > 4 baz:4
+  > 5
+  > 6
+  > EOF
+  $ hg ci -m 'baz: narrow change (2->2+)'
+  $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:4, startrev=20, descend=True)' --graph
+  @  33: baz: narrow change (2->2+)
+  |
+  o    32: merge forgetting about baz rewrite
+  |\
+  | o  31: baz: mostly rewrite with some content from 24
+  | :
+  | : o  30: baz:3->+3
+  | :/
+  +---o  27: baz:3+->3-
+  | :
+  o :  24: baz:3->3+
+  :/
+  o    20: baz:4
+  |\
+  ~ ~
+
 check error cases
   $ hg up 24 --quiet
   $ hg log -r 'followlines()'