Patchwork followlines: join merge parents line ranges in blockdescendants() (issue5595)

login
register
mail settings
Submitter Denis Laxalde
Date July 5, 2017, 12:31 p.m.
Message ID <279d73fea8a821f2a87b.1499257896@sh77.tls.logilab.fr>
Download mbox | patch
Permalink /patch/22011/
State Accepted
Headers show

Comments

Denis Laxalde - July 5, 2017, 12:31 p.m.
# HG changeset patch
# User Denis Laxalde <denis.laxalde@logilab.fr>
# Date 1499255693 -7200
#      Wed Jul 05 13:54:53 2017 +0200
# Node ID 279d73fea8a821f2a87bb040feed7daf9e162f0d
# Parent  5c9ad50fd62fbc2057ef7b44f921f22e7359af32
# Available At http://hg.logilab.org/users/dlaxalde/hg
#              hg pull http://hg.logilab.org/users/dlaxalde/hg -r 279d73fea8a8
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).
Yuya Nishihara - July 6, 2017, 2:20 p.m.
On Wed, 05 Jul 2017 14:31:36 +0200, Denis Laxalde wrote:
> # HG changeset patch
> # User Denis Laxalde <denis.laxalde@logilab.fr>
> # Date 1499255693 -7200
> #      Wed Jul 05 13:54:53 2017 +0200
> # Node ID 279d73fea8a821f2a87bb040feed7daf9e162f0d
> # Parent  5c9ad50fd62fbc2057ef7b44f921f22e7359af32
> # Available At http://hg.logilab.org/users/dlaxalde/hg
> #              hg pull http://hg.logilab.org/users/dlaxalde/hg -r 279d73fea8a8
> 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).

Sounds good. Queued, thanks.

Patch

diff --git a/mercurial/dagop.py b/mercurial/dagop.py
--- a/mercurial/dagop.py
+++ b/mercurial/dagop.py
@@ -287,12 +287,13 @@  def blockdescendants(fctx, fromline, tol
                 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
diff --git a/tests/test-annotate.t b/tests/test-annotate.t
--- a/tests/test-annotate.t
+++ b/tests/test-annotate.t
@@ -725,6 +725,65 @@  we follow all branches in descending dir
   |
   ~
 
+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()'