mercurial/localrepo.py
changeset 45203 ae5c1a3bc339
parent 45202 31393ec06cef
child 45204 ce9ee81df9ff
equal deleted inserted replaced
45202:31393ec06cef 45203:ae5c1a3bc339
    30     bookmarks,
    30     bookmarks,
    31     branchmap,
    31     branchmap,
    32     bundle2,
    32     bundle2,
    33     changegroup,
    33     changegroup,
    34     color,
    34     color,
       
    35     commit,
    35     context,
    36     context,
    36     dirstate,
    37     dirstate,
    37     dirstateguard,
    38     dirstateguard,
    38     discovery,
    39     discovery,
    39     encoding,
    40     encoding,
    44     hook,
    45     hook,
    45     lock as lockmod,
    46     lock as lockmod,
    46     match as matchmod,
    47     match as matchmod,
    47     mergestate as mergestatemod,
    48     mergestate as mergestatemod,
    48     mergeutil,
    49     mergeutil,
    49     metadata,
       
    50     namespaces,
    50     namespaces,
    51     narrowspec,
    51     narrowspec,
    52     obsolete,
    52     obsolete,
    53     pathutil,
    53     pathutil,
    54     phases,
    54     phases,
  3065         self._afterlock(commithook)
  3065         self._afterlock(commithook)
  3066         return ret
  3066         return ret
  3067 
  3067 
  3068     @unfilteredmethod
  3068     @unfilteredmethod
  3069     def commitctx(self, ctx, error=False, origctx=None):
  3069     def commitctx(self, ctx, error=False, origctx=None):
  3070         """Add a new revision to current repository.
  3070         return commit.commitctx(self, ctx, error=error, origctx=origctx)
  3071         Revision information is passed via the context argument.
       
  3072 
       
  3073         ctx.files() should list all files involved in this commit, i.e.
       
  3074         modified/added/removed files. On merge, it may be wider than the
       
  3075         ctx.files() to be committed, since any file nodes derived directly
       
  3076         from p1 or p2 are excluded from the committed ctx.files().
       
  3077 
       
  3078         origctx is for convert to work around the problem that bug
       
  3079         fixes to the files list in changesets change hashes. For
       
  3080         convert to be the identity, it can pass an origctx and this
       
  3081         function will use the same files list when it makes sense to
       
  3082         do so.
       
  3083         """
       
  3084 
       
  3085         p1, p2 = ctx.p1(), ctx.p2()
       
  3086         user = ctx.user()
       
  3087 
       
  3088         if self.filecopiesmode == b'changeset-sidedata':
       
  3089             writechangesetcopy = True
       
  3090             writefilecopymeta = True
       
  3091             writecopiesto = None
       
  3092         else:
       
  3093             writecopiesto = self.ui.config(b'experimental', b'copies.write-to')
       
  3094             writefilecopymeta = writecopiesto != b'changeset-only'
       
  3095             writechangesetcopy = writecopiesto in (
       
  3096                 b'changeset-only',
       
  3097                 b'compatibility',
       
  3098             )
       
  3099         p1copies, p2copies = None, None
       
  3100         if writechangesetcopy:
       
  3101             p1copies = ctx.p1copies()
       
  3102             p2copies = ctx.p2copies()
       
  3103         filesadded, filesremoved = None, None
       
  3104         with self.lock(), self.transaction(b"commit") as tr:
       
  3105             trp = weakref.proxy(tr)
       
  3106 
       
  3107             if ctx.manifestnode():
       
  3108                 # reuse an existing manifest revision
       
  3109                 self.ui.debug(b'reusing known manifest\n')
       
  3110                 mn = ctx.manifestnode()
       
  3111                 files = ctx.files()
       
  3112                 if writechangesetcopy:
       
  3113                     filesadded = ctx.filesadded()
       
  3114                     filesremoved = ctx.filesremoved()
       
  3115             elif not ctx.files():
       
  3116                 self.ui.debug(b'reusing manifest from p1 (no file change)\n')
       
  3117                 mn = p1.manifestnode()
       
  3118                 files = []
       
  3119             else:
       
  3120                 m1ctx = p1.manifestctx()
       
  3121                 m2ctx = p2.manifestctx()
       
  3122                 mctx = m1ctx.copy()
       
  3123 
       
  3124                 m = mctx.read()
       
  3125                 m1 = m1ctx.read()
       
  3126                 m2 = m2ctx.read()
       
  3127 
       
  3128                 # check in files
       
  3129                 added = []
       
  3130                 filesadded = []
       
  3131                 removed = list(ctx.removed())
       
  3132                 touched = []
       
  3133                 linkrev = len(self)
       
  3134                 self.ui.note(_(b"committing files:\n"))
       
  3135                 uipathfn = scmutil.getuipathfn(self)
       
  3136                 for f in sorted(ctx.modified() + ctx.added()):
       
  3137                     self.ui.note(uipathfn(f) + b"\n")
       
  3138                     try:
       
  3139                         fctx = ctx[f]
       
  3140                         if fctx is None:
       
  3141                             removed.append(f)
       
  3142                         else:
       
  3143                             added.append(f)
       
  3144                             m[f], is_touched = self._filecommit(
       
  3145                                 fctx, m1, m2, linkrev, trp, writefilecopymeta,
       
  3146                             )
       
  3147                             if is_touched:
       
  3148                                 touched.append(f)
       
  3149                                 if writechangesetcopy and is_touched == 'added':
       
  3150                                     filesadded.append(f)
       
  3151                             m.setflag(f, fctx.flags())
       
  3152                     except OSError:
       
  3153                         self.ui.warn(
       
  3154                             _(b"trouble committing %s!\n") % uipathfn(f)
       
  3155                         )
       
  3156                         raise
       
  3157                     except IOError as inst:
       
  3158                         errcode = getattr(inst, 'errno', errno.ENOENT)
       
  3159                         if error or errcode and errcode != errno.ENOENT:
       
  3160                             self.ui.warn(
       
  3161                                 _(b"trouble committing %s!\n") % uipathfn(f)
       
  3162                             )
       
  3163                         raise
       
  3164 
       
  3165                 # update manifest
       
  3166                 removed = [f for f in removed if f in m1 or f in m2]
       
  3167                 drop = sorted([f for f in removed if f in m])
       
  3168                 for f in drop:
       
  3169                     del m[f]
       
  3170                 if p2.rev() != nullrev:
       
  3171                     rf = metadata.get_removal_filter(ctx, (p1, p2, m1, m2))
       
  3172                     removed = [f for f in removed if not rf(f)]
       
  3173 
       
  3174                 touched.extend(removed)
       
  3175 
       
  3176                 if writechangesetcopy:
       
  3177                     filesremoved = removed
       
  3178 
       
  3179                 files = touched
       
  3180                 md = None
       
  3181                 if not files:
       
  3182                     # if no "files" actually changed in terms of the changelog,
       
  3183                     # try hard to detect unmodified manifest entry so that the
       
  3184                     # exact same commit can be reproduced later on convert.
       
  3185                     md = m1.diff(m, scmutil.matchfiles(self, ctx.files()))
       
  3186                 if not files and md:
       
  3187                     self.ui.debug(
       
  3188                         b'not reusing manifest (no file change in '
       
  3189                         b'changelog, but manifest differs)\n'
       
  3190                     )
       
  3191                 if files or md:
       
  3192                     self.ui.note(_(b"committing manifest\n"))
       
  3193                     # we're using narrowmatch here since it's already applied at
       
  3194                     # other stages (such as dirstate.walk), so we're already
       
  3195                     # ignoring things outside of narrowspec in most cases. The
       
  3196                     # one case where we might have files outside the narrowspec
       
  3197                     # at this point is merges, and we already error out in the
       
  3198                     # case where the merge has files outside of the narrowspec,
       
  3199                     # so this is safe.
       
  3200                     mn = mctx.write(
       
  3201                         trp,
       
  3202                         linkrev,
       
  3203                         p1.manifestnode(),
       
  3204                         p2.manifestnode(),
       
  3205                         added,
       
  3206                         drop,
       
  3207                         match=self.narrowmatch(),
       
  3208                     )
       
  3209                 else:
       
  3210                     self.ui.debug(
       
  3211                         b'reusing manifest from p1 (listed files '
       
  3212                         b'actually unchanged)\n'
       
  3213                     )
       
  3214                     mn = p1.manifestnode()
       
  3215 
       
  3216             if writecopiesto == b'changeset-only':
       
  3217                 # If writing only to changeset extras, use None to indicate that
       
  3218                 # no entry should be written. If writing to both, write an empty
       
  3219                 # entry to prevent the reader from falling back to reading
       
  3220                 # filelogs.
       
  3221                 p1copies = p1copies or None
       
  3222                 p2copies = p2copies or None
       
  3223                 filesadded = filesadded or None
       
  3224                 filesremoved = filesremoved or None
       
  3225 
       
  3226             if origctx and origctx.manifestnode() == mn:
       
  3227                 files = origctx.files()
       
  3228 
       
  3229             # update changelog
       
  3230             self.ui.note(_(b"committing changelog\n"))
       
  3231             self.changelog.delayupdate(tr)
       
  3232             n = self.changelog.add(
       
  3233                 mn,
       
  3234                 files,
       
  3235                 ctx.description(),
       
  3236                 trp,
       
  3237                 p1.node(),
       
  3238                 p2.node(),
       
  3239                 user,
       
  3240                 ctx.date(),
       
  3241                 ctx.extra().copy(),
       
  3242                 p1copies,
       
  3243                 p2copies,
       
  3244                 filesadded,
       
  3245                 filesremoved,
       
  3246             )
       
  3247             xp1, xp2 = p1.hex(), p2 and p2.hex() or b''
       
  3248             self.hook(
       
  3249                 b'pretxncommit',
       
  3250                 throw=True,
       
  3251                 node=hex(n),
       
  3252                 parent1=xp1,
       
  3253                 parent2=xp2,
       
  3254             )
       
  3255             # set the new commit is proper phase
       
  3256             targetphase = subrepoutil.newcommitphase(self.ui, ctx)
       
  3257             if targetphase:
       
  3258                 # retract boundary do not alter parent changeset.
       
  3259                 # if a parent have higher the resulting phase will
       
  3260                 # be compliant anyway
       
  3261                 #
       
  3262                 # if minimal phase was 0 we don't need to retract anything
       
  3263                 phases.registernew(self, tr, targetphase, [n])
       
  3264             return n
       
  3265 
  3071 
  3266     @unfilteredmethod
  3072     @unfilteredmethod
  3267     def destroying(self):
  3073     def destroying(self):
  3268         '''Inform the repository that nodes are about to be destroyed.
  3074         '''Inform the repository that nodes are about to be destroyed.
  3269         Intended for use by strip and rollback, so there's a common
  3075         Intended for use by strip and rollback, so there's a common