--- a/mercurial/context.py Wed Dec 31 17:55:43 2014 +0900
+++ b/mercurial/context.py Tue Dec 23 15:30:38 2014 -0800
@@ -22,6 +22,40 @@
# dirty in the working copy.
_newnode = '!' * 21
+def _adjustlinkrev(repo, path, filelog, fnode, srcrev):
+ """return the first ancestor of <srcrev> introducting <fnode>
+
+ If the linkrev of the file revision does not point to an ancestor of
+ srcrev, we'll walk down the ancestors until we find one introducing this
+ file revision.
+
+ :repo: a localrepository object (used to access changelog and manifest)
+ :path: the file path
+ :fnode: the nodeid of the file revision
+ :filelog: the filelog of this path
+ :srcrev: the changeset revision we search ancestors from
+ """
+ cl = repo.unfiltered().changelog
+ ma = repo.manifest
+ # fetch the linkrev
+ fr = filelog.rev(fnode)
+ lkr = filelog.linkrev(fr)
+ # check if this linkrev is an ancestor of srcrev
+ anc = cl.ancestors([srcrev], lkr)
+ if lkr not in anc:
+ for a in anc:
+ ac = cl.read(a) # get changeset data (we avoid object creation).
+ if path in ac[3]: # checking the 'files' field.
+ # The file has been touched, check if the content is similar
+ # to the one we search for.
+ if fnode == ma.readdelta(ac[0]).get(path):
+ return a
+ # In theory, we should never get out of that loop without a result. But
+ # if manifest uses a buggy file revision (not children of the one it
+ # replaces) we could. Such a buggy situation will likely result is crash
+ # somewhere else at to some point.
+ return lkr
+
class basectx(object):
"""A basectx object represents the common logic for its children:
changectx: read-only context that is already present in the repo,
@@ -739,7 +773,7 @@
parents = self._filelog.parents(self._filenode)
pl = [(_path, node, fl) for node in parents if node != nullid]
- r = self._filelog.renamed(self._filenode)
+ r = fl.renamed(self._filenode)
if r:
# - In the simple rename case, both parent are nullid, pl is empty.
# - In case of merge, only one of the parent is null id and should
@@ -751,7 +785,19 @@
# first nullid parent with rename information.
pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
- return [filectx(self._repo, p, fileid=n, filelog=l) for p, n, l in pl]
+ ret = []
+ for path, fnode, l in pl:
+ if '_changeid' in vars(self) or '_changectx' in vars(self):
+ # If self is associated with a changeset (probably explicitly
+ # fed), ensure the created filectx is associated with a
+ # changeset that is an ancestor of self.changectx.
+ rev = _adjustlinkrev(self._repo, path, l, fnode, self.rev())
+ fctx = filectx(self._repo, path, fileid=fnode, filelog=l,
+ changeid=rev)
+ else:
+ fctx = filectx(self._repo, path, fileid=fnode, filelog=l)
+ ret.append(fctx)
+ return ret
def p1(self):
return self.parents()[0]