log: do not --follow file that is deleted and recreated later (issue732)
authorNicolas Dumazet <nicdumz.commits@gmail.com>
Sun, 15 Aug 2010 23:17:53 +0900
changeset 11899 99cafcae25d9
parent 11898 7dc8b9e25f19
child 11900 cd7182358d9f
log: do not --follow file that is deleted and recreated later (issue732) == What == issue732 is only one example of a buggy behaviour, but there are in fact many intricated cases. For example: ( "o" contains an alive version of the tracked file, "x" does not) tip - o - o - x - o - o - x ... \ o - o - o - o - x ... \ / o - o This repository contains at least two instances of the tracked file, but when calling "hg log -f file" only the latest one (the one alive in tip) matters to us. == How == We must extract from the filelog the history of the file instance we're interested in and discard changes related to other instances of that file. We see that we're only interested in ancestors(node), and that all other nodes in the filelog should not be considered.
mercurial/cmdutil.py
tests/test-log
tests/test-log.out
tests/test-mq-caches.t
tests/test-mq-eol.t
tests/test-mq-guards.t
tests/test-mq-safety.t
tests/test-mq.t
--- a/mercurial/cmdutil.py	Sun Aug 15 22:44:15 2010 +0900
+++ b/mercurial/cmdutil.py	Sun Aug 15 23:17:53 2010 +0900
@@ -1059,8 +1059,14 @@
         # We only have to read through the filelog to find wanted revisions
 
         minrev, maxrev = min(revs), max(revs)
-        # Only files, no patterns.  Check the history of each file.
         def filerevgen(filelog, last):
+            """
+            Only files, no patterns.  Check the history of each file.
+
+            Examines filelog entries within minrev, maxrev linkrev range
+            Returns an iterator yielding (linkrev, parentlinkrevs, copied)
+            tuples in backwards order
+            """
             cl_count = len(repo)
             revs = []
             for j in xrange(0, last + 1):
@@ -1071,8 +1077,13 @@
                 # happen while doing "hg log" during a pull or commit
                 if linkrev > maxrev or linkrev >= cl_count:
                     break
+
+                parentlinkrevs = []
+                for p in filelog.parentrevs(j):
+                    if p != nullrev:
+                        parentlinkrevs.append(filelog.linkrev(p))
                 n = filelog.node(j)
-                revs.append((filelog.linkrev(j),
+                revs.append((linkrev, parentlinkrevs,
                              follow and filelog.renamed(n)))
 
             for rev in reversed(revs):
@@ -1101,7 +1112,18 @@
             else:
                 last = filelog.rev(node)
 
-            for rev, copied in filerevgen(filelog, last):
+
+            # keep track of all ancestors of the file
+            ancestors = set([filelog.linkrev(last)])
+
+            # iterate from latest to oldest revision
+            for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
+                if rev not in ancestors:
+                    continue
+                # XXX insert 1327 fix here
+                if flparentlinkrevs:
+                    ancestors.update(flparentlinkrevs)
+
                 fncache.setdefault(rev, [])
                 fncache[rev].append(file_)
                 wanted.add(rev)
--- a/tests/test-log	Sun Aug 15 22:44:15 2010 +0900
+++ b/tests/test-log	Sun Aug 15 23:17:53 2010 +0900
@@ -200,4 +200,53 @@
 hg log -p -R .. ../a
 
 
+cd ..
+hg init follow2
+cd follow2
+
+# Build the following history:
+# tip - o - x - o - x - x
+#    \                 /
+#     o - o - o - x
+#      \     /
+#         o
+#
+# Where "o" is a revision containing "foo" and
+# "x" is a revision without "foo"
+touch init
+hg ci -A -m "init, unrelated"
+echo 'foo' > init
+hg ci -m "change, unrelated"
+echo 'foo' > foo
+hg ci -A -m "add unrelated old foo"
+hg rm foo
+hg ci -m "delete foo, unrelated"
+echo 'related' > foo
+hg ci -A -m "add foo, related"
+
+hg up 0
+touch branch
+hg ci -A -m "first branch, unrelated"
+touch foo
+hg ci -A -m "create foo, related"
+echo 'change' > foo
+hg ci -m "change foo, related"
+
+hg up 6
+echo 'change foo in branch' > foo
+hg ci -m "change foo in branch, related"
+hg merge 7
+echo 'merge 1' > foo
+hg resolve -m foo
+hg ci -m "First merge, related"
+
+hg merge 4
+echo 'merge 2' > foo
+hg resolve -m foo
+hg ci -m "Last merge, related"
+
+hg --config "extensions.graphlog=" glog
+
+hg --traceback log -f foo
+
 exit 0
--- a/tests/test-log.out	Sun Aug 15 22:44:15 2010 +0900
+++ b/tests/test-log.out	Sun Aug 15 23:17:53 2010 +0900
@@ -611,3 +611,120 @@
 @@ -0,0 +1,1 @@
 +a
 
+adding init
+adding foo
+adding foo
+1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding branch
+created new head
+adding foo
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+created new head
+merging foo
+warning: conflicts during merge.
+merging foo failed!
+0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
+merging foo
+warning: conflicts during merge.
+merging foo failed!
+1 files updated, 0 files merged, 0 files removed, 1 files unresolved
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
+@    changeset:   10:4dae8563d2c5
+|\   tag:         tip
+| |  parent:      9:7b35701b003e
+| |  parent:      4:88176d361b69
+| |  user:        test
+| |  date:        Thu Jan 01 00:00:00 1970 +0000
+| |  summary:     Last merge, related
+| |
+| o    changeset:   9:7b35701b003e
+| |\   parent:      8:e5416ad8a855
+| | |  parent:      7:87fe3144dcfa
+| | |  user:        test
+| | |  date:        Thu Jan 01 00:00:00 1970 +0000
+| | |  summary:     First merge, related
+| | |
+| | o  changeset:   8:e5416ad8a855
+| | |  parent:      6:dc6c325fe5ee
+| | |  user:        test
+| | |  date:        Thu Jan 01 00:00:00 1970 +0000
+| | |  summary:     change foo in branch, related
+| | |
+| o |  changeset:   7:87fe3144dcfa
+| |/   user:        test
+| |    date:        Thu Jan 01 00:00:00 1970 +0000
+| |    summary:     change foo, related
+| |
+| o  changeset:   6:dc6c325fe5ee
+| |  user:        test
+| |  date:        Thu Jan 01 00:00:00 1970 +0000
+| |  summary:     create foo, related
+| |
+| o  changeset:   5:73db34516eb9
+| |  parent:      0:e87515fd044a
+| |  user:        test
+| |  date:        Thu Jan 01 00:00:00 1970 +0000
+| |  summary:     first branch, unrelated
+| |
+o |  changeset:   4:88176d361b69
+| |  user:        test
+| |  date:        Thu Jan 01 00:00:00 1970 +0000
+| |  summary:     add foo, related
+| |
+o |  changeset:   3:dd78ae4afb56
+| |  user:        test
+| |  date:        Thu Jan 01 00:00:00 1970 +0000
+| |  summary:     delete foo, unrelated
+| |
+o |  changeset:   2:c4c64aedf0f7
+| |  user:        test
+| |  date:        Thu Jan 01 00:00:00 1970 +0000
+| |  summary:     add unrelated old foo
+| |
+o |  changeset:   1:e5faa7440653
+|/   user:        test
+|    date:        Thu Jan 01 00:00:00 1970 +0000
+|    summary:     change, unrelated
+|
+o  changeset:   0:e87515fd044a
+   user:        test
+   date:        Thu Jan 01 00:00:00 1970 +0000
+   summary:     init, unrelated
+
+changeset:   10:4dae8563d2c5
+tag:         tip
+parent:      9:7b35701b003e
+parent:      4:88176d361b69
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     Last merge, related
+
+changeset:   9:7b35701b003e
+parent:      8:e5416ad8a855
+parent:      7:87fe3144dcfa
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     First merge, related
+
+changeset:   8:e5416ad8a855
+parent:      6:dc6c325fe5ee
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     change foo in branch, related
+
+changeset:   7:87fe3144dcfa
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     change foo, related
+
+changeset:   6:dc6c325fe5ee
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     create foo, related
+
+changeset:   4:88176d361b69
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add foo, related
+