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 |