Patchwork [STABLE,V2] log: fix order of revisions filtered by multiple OR options (issue5100)

login
register
mail settings
Submitter Yuya Nishihara
Date Feb. 26, 2016, 4:09 p.m.
Message ID <fa74c35467a7ed0d1149.1456502995@mimosa>
Download mbox | patch
Permalink /patch/13418/
State Accepted
Headers show

Comments

Yuya Nishihara - Feb. 26, 2016, 4:09 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1455543967 -32400
#      Mon Feb 15 22:46:07 2016 +0900
# Branch stable
# Node ID fa74c35467a7ed0d11493e3e469629c8477f8c9b
# Parent  cb6a952efbf48d306a7c82d7fe46115f072cbb1d
log: fix order of revisions filtered by multiple OR options (issue5100)

This is the simplest workaround for the issue of the ordering of revset, which
is that the expression "x or y" takes over the ordering specified by the input
set (or the left-hand-side expression.) For example, the following expression

  A & (x | y)

will be evaluated as if

  (A & x) | (A & y)

That's wrong because revset has ordering. I'm going to fix this problem in
the revset module, but that wouldn't fit to stable. So, this patch just works
around the common log cases.

Since this change might have some impact on performance, it is enabled only
if the expression built from log options has ' or ' operation.
Pierre-Yves David - Feb. 26, 2016, 9:40 p.m.
On 02/26/2016 05:09 PM, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1455543967 -32400
> #      Mon Feb 15 22:46:07 2016 +0900
> # Branch stable
> # Node ID fa74c35467a7ed0d11493e3e469629c8477f8c9b
> # Parent  cb6a952efbf48d306a7c82d7fe46115f072cbb1d
> log: fix order of revisions filtered by multiple OR options (issue5100)

Pushed to the clowncopter. Thanks.

Patch

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -2139,9 +2139,15 @@  def getlogrevs(repo, pats, opts):
         # Revset matches can reorder revisions. "A or B" typically returns
         # returns the revision matching A then the revision matching B. Sort
         # again to fix that.
+        fixopts = ['branch', 'only_branch', 'keyword', 'user']
+        oldrevs = revs
         revs = matcher(repo, revs)
         if not opts.get('rev'):
             revs.sort(reverse=True)
+        elif len(pats) > 1 or any(len(opts.get(op, [])) > 1 for op in fixopts):
+            # XXX "A or B" is known to change the order; fix it by filtering
+            # matched set again (issue5100)
+            revs = oldrevs & revs
     if limit is not None:
         limitedrevs = []
         for idx, r in enumerate(revs):
diff --git a/tests/test-log.t b/tests/test-log.t
--- a/tests/test-log.t
+++ b/tests/test-log.t
@@ -920,6 +920,116 @@  log -r tip --stat
 
   $ cd ..
 
+Test that log should respect the order of -rREV even if multiple OR conditions
+are specified (issue5100):
+
+  $ hg init revorder
+  $ cd revorder
+
+  $ hg branch -q b0
+  $ echo 0 >> f0
+  $ hg ci -qAm k0 -u u0
+  $ hg branch -q b1
+  $ echo 1 >> f1
+  $ hg ci -qAm k1 -u u1
+  $ hg branch -q b2
+  $ echo 2 >> f2
+  $ hg ci -qAm k2 -u u2
+
+  $ hg update -q b2
+  $ echo 3 >> f2
+  $ hg ci -qAm k2 -u u2
+  $ hg update -q b1
+  $ echo 4 >> f1
+  $ hg ci -qAm k1 -u u1
+  $ hg update -q b0
+  $ echo 5 >> f0
+  $ hg ci -qAm k0 -u u0
+
+ summary of revisions:
+
+  $ hg log -G -T '{rev} {branch} {author} {desc} {files}\n'
+  @  5 b0 u0 k0 f0
+  |
+  | o  4 b1 u1 k1 f1
+  | |
+  | | o  3 b2 u2 k2 f2
+  | | |
+  | | o  2 b2 u2 k2 f2
+  | |/
+  | o  1 b1 u1 k1 f1
+  |/
+  o  0 b0 u0 k0 f0
+  
+
+ log -b BRANCH in ascending order:
+
+  $ hg log -r0:tip -T '{rev} {branch}\n' -b b0 -b b1
+  0 b0
+  1 b1
+  4 b1
+  5 b0
+  $ hg log -r0:tip -T '{rev} {branch}\n' -b b1 -b b0
+  0 b0
+  1 b1
+  4 b1
+  5 b0
+
+ log --only-branch BRANCH in descending order:
+
+  $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b1 --only-branch b2
+  4 b1
+  3 b2
+  2 b2
+  1 b1
+  $ hg log -rtip:0 -T '{rev} {branch}\n' --only-branch b2 --only-branch b1
+  4 b1
+  3 b2
+  2 b2
+  1 b1
+
+ log -u USER in ascending order, against compound set:
+
+  $ hg log -r'::head()' -T '{rev} {author}\n' -u u0 -u u2
+  0 u0
+  2 u2
+  3 u2
+  5 u0
+  $ hg log -r'::head()' -T '{rev} {author}\n' -u u2 -u u0
+  0 u0
+  2 u2
+  3 u2
+  5 u0
+
+ log -k TEXT in descending order, against compound set:
+
+  $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k0 -k k1 -k k2
+  5 k0
+  3 k2
+  2 k2
+  1 k1
+  0 k0
+  $ hg log -r'5 + reverse(::3)' -T '{rev} {desc}\n' -k k2 -k k1 -k k0
+  5 k0
+  3 k2
+  2 k2
+  1 k1
+  0 k0
+
+ log FILE in ascending order, against dagrange:
+
+  $ hg log -r1:: -T '{rev} {files}\n' f1 f2
+  1 f1
+  2 f2
+  3 f2
+  4 f1
+  $ hg log -r1:: -T '{rev} {files}\n' f2 f1
+  1 f1
+  2 f2
+  3 f2
+  4 f1
+
+  $ cd ..
 
 User