mercurial/context.py
changeset 23703 aaa76612b3c0
parent 23702 c48924787eaa
child 23705 28a302e9225d
--- a/mercurial/context.py	Tue Dec 23 15:30:38 2014 -0800
+++ b/mercurial/context.py	Tue Dec 23 16:14:39 2014 -0800
@@ -22,7 +22,7 @@
 # dirty in the working copy.
 _newnode = '!' * 21
 
-def _adjustlinkrev(repo, path, filelog, fnode, srcrev):
+def _adjustlinkrev(repo, path, filelog, fnode, srcrev, inclusive=False):
     """return the first ancestor of <srcrev> introducting <fnode>
 
     If the linkrev of the file revision does not point to an ancestor of
@@ -34,6 +34,7 @@
     :fnode: the nodeid of the file revision
     :filelog: the filelog of this path
     :srcrev: the changeset revision we search ancestors from
+    :inclusive: if true, the src revision will also be checked
     """
     cl = repo.unfiltered().changelog
     ma = repo.manifest
@@ -41,7 +42,7 @@
     fr = filelog.rev(fnode)
     lkr = filelog.linkrev(fr)
     # check if this linkrev is an ancestor of srcrev
-    anc = cl.ancestors([srcrev], lkr)
+    anc = cl.ancestors([srcrev], lkr, inclusive=inclusive)
     if lkr not in anc:
         for a in anc:
             ac = cl.read(a) # get changeset data (we avoid object creation).
@@ -767,6 +768,23 @@
 
         return True
 
+    def introrev(self):
+        """return the rev of the changeset which introduced this file revision
+
+        This method is different from linkrev because it take into account the
+        changeset the filectx was created from. It ensures the returned
+        revision is one of its ancestors. This prevents bugs from
+        'linkrev-shadowing' when a file revision is used by multiple
+        changesets.
+        """
+        lkr = self.linkrev()
+        attrs = vars(self)
+        noctx = not ('_changeid' in attrs or '_changectx' in attrs)
+        if noctx or self.rev() == lkr:
+            return self.linkrev()
+        return _adjustlinkrev(self._repo, self._path, self._filelog,
+                              self._filenode, self.rev(), inclusive=True)
+
     def parents(self):
         _path = self._path
         fl = self._filelog