comparison mercurial/localrepo.py @ 45204:ce9ee81df9ff

commitctx: extract _filecommit too This function is exclusively used in `commitctx`. So we should extract it too for consistency and to reduce the `localrepo` bloat. This is part of a larger refactoring/cleanup of the commitctx code to clarify and augment the logic gathering metadata useful for copy tracing. The current code is a tad too long and entangled to make such update easy. Differential Revision: https://phab.mercurial-scm.org/D8710
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 07 Jul 2020 00:18:15 +0200
parents ae5c1a3bc339
children dc457177dbc1
comparison
equal deleted inserted replaced
45203:ae5c1a3bc339 45204:ce9ee81df9ff
2769 2769
2770 def currentwlock(self): 2770 def currentwlock(self):
2771 """Returns the wlock if it's held, or None if it's not.""" 2771 """Returns the wlock if it's held, or None if it's not."""
2772 return self._currentlock(self._wlockref) 2772 return self._currentlock(self._wlockref)
2773 2773
2774 def _filecommit(
2775 self, fctx, manifest1, manifest2, linkrev, tr, includecopymeta,
2776 ):
2777 """
2778 commit an individual file as part of a larger transaction
2779
2780 input:
2781
2782 fctx: a file context with the content we are trying to commit
2783 manifest1: manifest of changeset first parent
2784 manifest2: manifest of changeset second parent
2785 linkrev: revision number of the changeset being created
2786 tr: current transation
2787 individual: boolean, set to False to skip storing the copy data
2788 (only used by the Google specific feature of using
2789 changeset extra as copy source of truth).
2790
2791 output: (filenode, touched)
2792
2793 filenode: the filenode that should be used by this changeset
2794 touched: one of: None, 'added' or 'modified'
2795 """
2796
2797 fname = fctx.path()
2798 fparent1 = manifest1.get(fname, nullid)
2799 fparent2 = manifest2.get(fname, nullid)
2800 touched = None
2801 if fparent1 == fparent2 == nullid:
2802 touched = 'added'
2803
2804 if isinstance(fctx, context.filectx):
2805 # This block fast path most comparisons which are usually done. It
2806 # assumes that bare filectx is used and no merge happened, hence no
2807 # need to create a new file revision in this case.
2808 node = fctx.filenode()
2809 if node in [fparent1, fparent2]:
2810 self.ui.debug(b'reusing %s filelog entry\n' % fname)
2811 if (
2812 fparent1 != nullid
2813 and manifest1.flags(fname) != fctx.flags()
2814 ) or (
2815 fparent2 != nullid
2816 and manifest2.flags(fname) != fctx.flags()
2817 ):
2818 touched = 'modified'
2819 return node, touched
2820
2821 flog = self.file(fname)
2822 meta = {}
2823 cfname = fctx.copysource()
2824 fnode = None
2825
2826 if cfname and cfname != fname:
2827 # Mark the new revision of this file as a copy of another
2828 # file. This copy data will effectively act as a parent
2829 # of this new revision. If this is a merge, the first
2830 # parent will be the nullid (meaning "look up the copy data")
2831 # and the second one will be the other parent. For example:
2832 #
2833 # 0 --- 1 --- 3 rev1 changes file foo
2834 # \ / rev2 renames foo to bar and changes it
2835 # \- 2 -/ rev3 should have bar with all changes and
2836 # should record that bar descends from
2837 # bar in rev2 and foo in rev1
2838 #
2839 # this allows this merge to succeed:
2840 #
2841 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
2842 # \ / merging rev3 and rev4 should use bar@rev2
2843 # \- 2 --- 4 as the merge base
2844 #
2845
2846 cnode = manifest1.get(cfname)
2847 newfparent = fparent2
2848
2849 if manifest2: # branch merge
2850 if fparent2 == nullid or cnode is None: # copied on remote side
2851 if cfname in manifest2:
2852 cnode = manifest2[cfname]
2853 newfparent = fparent1
2854
2855 # Here, we used to search backwards through history to try to find
2856 # where the file copy came from if the source of a copy was not in
2857 # the parent directory. However, this doesn't actually make sense to
2858 # do (what does a copy from something not in your working copy even
2859 # mean?) and it causes bugs (eg, issue4476). Instead, we will warn
2860 # the user that copy information was dropped, so if they didn't
2861 # expect this outcome it can be fixed, but this is the correct
2862 # behavior in this circumstance.
2863
2864 if cnode:
2865 self.ui.debug(
2866 b" %s: copy %s:%s\n" % (fname, cfname, hex(cnode))
2867 )
2868 if includecopymeta:
2869 meta[b"copy"] = cfname
2870 meta[b"copyrev"] = hex(cnode)
2871 fparent1, fparent2 = nullid, newfparent
2872 else:
2873 self.ui.warn(
2874 _(
2875 b"warning: can't find ancestor for '%s' "
2876 b"copied from '%s'!\n"
2877 )
2878 % (fname, cfname)
2879 )
2880
2881 elif fparent1 == nullid:
2882 fparent1, fparent2 = fparent2, nullid
2883 elif fparent2 != nullid:
2884 # is one parent an ancestor of the other?
2885 fparentancestors = flog.commonancestorsheads(fparent1, fparent2)
2886 if fparent1 in fparentancestors:
2887 fparent1, fparent2 = fparent2, nullid
2888 elif fparent2 in fparentancestors:
2889 fparent2 = nullid
2890 elif not fparentancestors:
2891 # TODO: this whole if-else might be simplified much more
2892 ms = mergestatemod.mergestate.read(self)
2893 if (
2894 fname in ms
2895 and ms[fname] == mergestatemod.MERGE_RECORD_MERGED_OTHER
2896 ):
2897 fparent1, fparent2 = fparent2, nullid
2898
2899 # is the file changed?
2900 text = fctx.data()
2901 if fparent2 != nullid or meta or flog.cmp(fparent1, text):
2902 if touched is None: # do not overwrite added
2903 touched = 'modified'
2904 fnode = flog.add(text, meta, tr, linkrev, fparent1, fparent2)
2905 # are just the flags changed during merge?
2906 elif fname in manifest1 and manifest1.flags(fname) != fctx.flags():
2907 touched = 'modified'
2908 fnode = fparent1
2909 else:
2910 fnode = fparent1
2911 return fnode, touched
2912
2913 def checkcommitpatterns(self, wctx, match, status, fail): 2774 def checkcommitpatterns(self, wctx, match, status, fail):
2914 """check for commit arguments that aren't committable""" 2775 """check for commit arguments that aren't committable"""
2915 if match.isexact() or match.prefix(): 2776 if match.isexact() or match.prefix():
2916 matched = set(status.modified + status.added + status.removed) 2777 matched = set(status.modified + status.added + status.removed)
2917 2778