in eden/scm/edenscm/mercurial/localrepo.py [0:0]
def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
"""
commit an individual file as part of a larger transaction
"""
fname = fctx.path()
fparent1 = manifest1.get(fname, nullid)
fparent2 = manifest2.get(fname, nullid)
node = fctx.filenode()
if node in [fparent1, fparent2]:
self.ui.debug("reusing %s filelog entry (parent match)\n" % fname)
if node == fparent1:
if manifest1.flags(fname) != fctx.flags():
changelist.append(fname)
else:
if manifest2.flags(fname) != fctx.flags():
changelist.append(fname)
return node
flog = self.file(fname)
meta = {}
copy = fctx.renamed()
# Is filelog metadata (currently only the copy information) unchanged?
# If it is, then filenode hash could be unchanged if data is also known
# unchanged. This allows fast path of adding new file nodes without
# calculating .data() or new hash.
#
# Metadata is unchanged if there is no copy information.
# Otherwise, the "copy from" revision needs to be checked.
metamatched = not bool(copy)
if copy and copy[0] != fname:
# Mark the new revision of this file as a copy of another
# file. This copy data will effectively act as a parent
# of this new revision. If this is a merge, the first
# parent will be the nullid (meaning "look up the copy data")
# and the second one will be the other parent. For example:
#
# 0 --- 1 --- 3 rev1 changes file foo
# \ / rev2 renames foo to bar and changes it
# \- 2 -/ rev3 should have bar with all changes and
# should record that bar descends from
# bar in rev2 and foo in rev1
#
# this allows this merge to succeed:
#
# 0 --- 1 --- 3 rev4 reverts the content change from rev2
# \ / merging rev3 and rev4 should use bar@rev2
# \- 2 --- 4 as the merge base
#
cfname, oldcrev = copy
crev = manifest1.get(cfname)
newfparent = fparent2
if manifest2: # branch merge
if fparent2 == nullid or crev is None: # copied on remote side
if cfname in manifest2:
crev = manifest2[cfname]
newfparent = fparent1
# Here, we used to search backwards through history to try to find
# where the file copy came from if the source of a copy was not in
# the parent directory. However, this doesn't actually make sense to
# do (what does a copy from something not in your working copy even
# mean?) and it causes bugs (eg, issue4476). Instead, we will warn
# the user that copy information was dropped, so if they didn't
# expect this outcome it can be fixed, but this is the correct
# behavior in this circumstance.
if crev:
self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
meta["copy"] = cfname
meta["copyrev"] = hex(crev)
metamatched = crev == oldcrev
fparent1, fparent2 = nullid, newfparent
else:
self.ui.warn(
_("warning: can't find ancestor for '%s' " "copied from '%s'!\n")
% (fname, cfname)
)
elif fparent1 == nullid:
fparent1, fparent2 = fparent2, nullid
elif fparent2 != nullid:
# is one parent an ancestor of the other?
fparentancestors = flog.commonancestorsheads(fparent1, fparent2)
if fparent1 in fparentancestors:
fparent1, fparent2 = fparent2, nullid
elif fparent2 in fparentancestors:
fparent2 = nullid
# Fast path: reuse rawdata? (skip .data() (ex. flagprocessors) and hash
# calculation)
if (
metamatched
and node is not None
# some filectxs do not support rawdata or flags
and util.safehasattr(fctx, "rawdata")
and util.safehasattr(fctx, "rawflags")
# some (external) filelogs do not have addrawrevision
and util.safehasattr(flog, "addrawrevision")
# parents must match to be able to reuse rawdata
and fctx.filelog().parents(node) == (fparent1, fparent2)
):
# node is different from fparents, no need to check manifest flag
changelist.append(fname)
if node in flog.nodemap:
self.ui.debug("reusing %s filelog node (exact match)\n" % fname)
return node
self.ui.debug("reusing %s filelog rawdata\n" % fname)
return flog.addrawrevision(
fctx.rawdata(), tr, linkrev, fparent1, fparent2, node, fctx.rawflags()
)
# is the file changed?
text = fctx.data()
if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
changelist.append(fname)
return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
# are just the flags changed during merge?
elif fname in manifest1 and manifest1.flags(fname) != fctx.flags():
changelist.append(fname)
return fparent1