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).
--- 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()'