Mercurial > public > mercurial-scm > hg
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 |