comparison mercurial/cmdutil.py @ 41605:7068c6b0114b

revert: respect ui.relative-paths Differential Revision: https://phab.mercurial-scm.org/D5874
author Martin von Zweigbergk <martinvonz@google.com>
date Tue, 05 Feb 2019 10:30:05 -0800
parents 9e545c9a4dfe
children 93620a4ba88d
comparison
equal deleted inserted replaced
41604:e944cf4ce1a8 41605:7068c6b0114b
2780 2780
2781 # `names` is a mapping for all elements in working copy and target revision 2781 # `names` is a mapping for all elements in working copy and target revision
2782 # The mapping is in the form: 2782 # The mapping is in the form:
2783 # <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>) 2783 # <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2784 names = {} 2784 names = {}
2785 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2785 2786
2786 with repo.wlock(): 2787 with repo.wlock():
2787 ## filling of the `names` mapping 2788 ## filling of the `names` mapping
2788 # walk dirstate to fill `names` 2789 # walk dirstate to fill `names`
2789 2790
2795 targetsubs = sorted(s for s in wctx.substate if m(s)) 2796 targetsubs = sorted(s for s in wctx.substate if m(s))
2796 2797
2797 if not m.always(): 2798 if not m.always():
2798 matcher = matchmod.badmatch(m, lambda x, y: False) 2799 matcher = matchmod.badmatch(m, lambda x, y: False)
2799 for abs in wctx.walk(matcher): 2800 for abs in wctx.walk(matcher):
2800 names[abs] = m.rel(abs), m.exact(abs) 2801 names[abs] = m.exact(abs)
2801 2802
2802 # walk target manifest to fill `names` 2803 # walk target manifest to fill `names`
2803 2804
2804 def badfn(path, msg): 2805 def badfn(path, msg):
2805 if path in names: 2806 if path in names:
2812 return 2813 return
2813 ui.warn("%s: %s\n" % (m.rel(path), msg)) 2814 ui.warn("%s: %s\n" % (m.rel(path), msg))
2814 2815
2815 for abs in ctx.walk(matchmod.badmatch(m, badfn)): 2816 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
2816 if abs not in names: 2817 if abs not in names:
2817 names[abs] = m.rel(abs), m.exact(abs) 2818 names[abs] = m.exact(abs)
2818 2819
2819 # Find status of all file in `names`. 2820 # Find status of all file in `names`.
2820 m = scmutil.matchfiles(repo, names) 2821 m = scmutil.matchfiles(repo, names)
2821 2822
2822 changes = repo.status(node1=node, match=m, 2823 changes = repo.status(node1=node, match=m,
2823 unknown=True, ignored=True, clean=True) 2824 unknown=True, ignored=True, clean=True)
2824 else: 2825 else:
2825 changes = repo.status(node1=node, match=m) 2826 changes = repo.status(node1=node, match=m)
2826 for kind in changes: 2827 for kind in changes:
2827 for abs in kind: 2828 for abs in kind:
2828 names[abs] = m.rel(abs), m.exact(abs) 2829 names[abs] = m.exact(abs)
2829 2830
2830 m = scmutil.matchfiles(repo, names) 2831 m = scmutil.matchfiles(repo, names)
2831 2832
2832 modified = set(changes.modified) 2833 modified = set(changes.modified)
2833 added = set(changes.added) 2834 added = set(changes.added)
2885 mergeadd.remove(path) 2886 mergeadd.remove(path)
2886 dsadded |= mergeadd 2887 dsadded |= mergeadd
2887 dsmodified -= mergeadd 2888 dsmodified -= mergeadd
2888 2889
2889 # if f is a rename, update `names` to also revert the source 2890 # if f is a rename, update `names` to also revert the source
2890 cwd = repo.getcwd()
2891 for f in localchanges: 2891 for f in localchanges:
2892 src = repo.dirstate.copied(f) 2892 src = repo.dirstate.copied(f)
2893 # XXX should we check for rename down to target node? 2893 # XXX should we check for rename down to target node?
2894 if src and src not in names and repo.dirstate[src] == 'r': 2894 if src and src not in names and repo.dirstate[src] == 'r':
2895 dsremoved.add(src) 2895 dsremoved.add(src)
2896 names[src] = (repo.pathto(src, cwd), True) 2896 names[src] = True
2897 2897
2898 # determine the exact nature of the deleted changesets 2898 # determine the exact nature of the deleted changesets
2899 deladded = set(_deleted) 2899 deladded = set(_deleted)
2900 for path in _deleted: 2900 for path in _deleted:
2901 if path in mf: 2901 if path in mf:
2998 (clean, actions['noop'], discard), 2998 (clean, actions['noop'], discard),
2999 # Existing file, not tracked anywhere 2999 # Existing file, not tracked anywhere
3000 (unknown, actions['unknown'], discard), 3000 (unknown, actions['unknown'], discard),
3001 ) 3001 )
3002 3002
3003 for abs, (rel, exact) in sorted(names.items()): 3003 for abs, exact in sorted(names.items()):
3004 # target file to be touch on disk (relative to cwd) 3004 # target file to be touch on disk (relative to cwd)
3005 target = repo.wjoin(abs) 3005 target = repo.wjoin(abs)
3006 # search the entry in the dispatch table. 3006 # search the entry in the dispatch table.
3007 # if the file is in any of these sets, it was touched in the working 3007 # if the file is in any of these sets, it was touched in the working
3008 # directory parent and we are sure it needs to be reverted. 3008 # directory parent and we are sure it needs to be reverted.
3015 # If in interactive mode, don't automatically create 3015 # If in interactive mode, don't automatically create
3016 # .orig files (issue4793) 3016 # .orig files (issue4793)
3017 if dobackup == backupinteractive: 3017 if dobackup == backupinteractive:
3018 tobackup.add(abs) 3018 tobackup.add(abs)
3019 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])): 3019 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
3020 bakname = scmutil.backuppath(ui, repo, abs) 3020 absbakname = scmutil.backuppath(ui, repo, abs)
3021 relbakname = os.path.relpath(bakname) 3021 bakname = os.path.relpath(absbakname,
3022 start=repo.root)
3022 ui.note(_('saving current version of %s as %s\n') % 3023 ui.note(_('saving current version of %s as %s\n') %
3023 (rel, relbakname)) 3024 (uipathfn(abs), uipathfn(bakname)))
3024 if not opts.get('dry_run'): 3025 if not opts.get('dry_run'):
3025 if interactive: 3026 if interactive:
3026 util.copyfile(target, bakname) 3027 util.copyfile(target, absbakname)
3027 else: 3028 else:
3028 util.rename(target, bakname) 3029 util.rename(target, absbakname)
3029 if opts.get('dry_run'): 3030 if opts.get('dry_run'):
3030 if ui.verbose or not exact: 3031 if ui.verbose or not exact:
3031 ui.status(msg % rel) 3032 ui.status(msg % uipathfn(abs))
3032 elif exact: 3033 elif exact:
3033 ui.warn(msg % rel) 3034 ui.warn(msg % uipathfn(abs))
3034 break 3035 break
3035 3036
3036 if not opts.get('dry_run'): 3037 if not opts.get('dry_run'):
3037 needdata = ('revert', 'add', 'undelete') 3038 needdata = ('revert', 'add', 'undelete')
3038 oplist = [actions[name][0] for name in needdata] 3039 oplist = [actions[name][0] for name in needdata]
3039 prefetch = scmutil.prefetchfiles 3040 prefetch = scmutil.prefetchfiles
3040 matchfiles = scmutil.matchfiles 3041 matchfiles = scmutil.matchfiles
3041 prefetch(repo, [ctx.rev()], 3042 prefetch(repo, [ctx.rev()],
3042 matchfiles(repo, 3043 matchfiles(repo,
3043 [f for sublist in oplist for f in sublist])) 3044 [f for sublist in oplist for f in sublist]))
3044 _performrevert(repo, parents, ctx, names, actions, interactive, 3045 _performrevert(repo, parents, ctx, names, uipathfn, actions,
3045 tobackup) 3046 interactive, tobackup)
3046 3047
3047 if targetsubs: 3048 if targetsubs:
3048 # Revert the subrepos on the revert list 3049 # Revert the subrepos on the revert list
3049 for sub in targetsubs: 3050 for sub in targetsubs:
3050 try: 3051 try:
3052 **pycompat.strkwargs(opts)) 3053 **pycompat.strkwargs(opts))
3053 except KeyError: 3054 except KeyError:
3054 raise error.Abort("subrepository '%s' does not exist in %s!" 3055 raise error.Abort("subrepository '%s' does not exist in %s!"
3055 % (sub, short(ctx.node()))) 3056 % (sub, short(ctx.node())))
3056 3057
3057 def _performrevert(repo, parents, ctx, names, actions, interactive=False, 3058 def _performrevert(repo, parents, ctx, names, uipathfn, actions,
3058 tobackup=None): 3059 interactive=False, tobackup=None):
3059 """function that actually perform all the actions computed for revert 3060 """function that actually perform all the actions computed for revert
3060 3061
3061 This is an independent function to let extension to plug in and react to 3062 This is an independent function to let extension to plug in and react to
3062 the imminent revert. 3063 the imminent revert.
3063 3064
3078 except OSError: 3079 except OSError:
3079 pass 3080 pass
3080 repo.dirstate.remove(f) 3081 repo.dirstate.remove(f)
3081 3082
3082 def prntstatusmsg(action, f): 3083 def prntstatusmsg(action, f):
3083 rel, exact = names[f] 3084 exact = names[f]
3084 if repo.ui.verbose or not exact: 3085 if repo.ui.verbose or not exact:
3085 repo.ui.status(actions[action][1] % rel) 3086 repo.ui.status(actions[action][1] % uipathfn(f))
3086 3087
3087 audit_path = pathutil.pathauditor(repo.root, cached=True) 3088 audit_path = pathutil.pathauditor(repo.root, cached=True)
3088 for f in actions['forget'][0]: 3089 for f in actions['forget'][0]:
3089 if interactive: 3090 if interactive:
3090 choice = repo.ui.promptchoice( 3091 choice = repo.ui.promptchoice(
3091 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f) 3092 _("forget added file %s (Yn)?$$ &Yes $$ &No") % uipathfn(f))
3092 if choice == 0: 3093 if choice == 0:
3093 prntstatusmsg('forget', f) 3094 prntstatusmsg('forget', f)
3094 repo.dirstate.drop(f) 3095 repo.dirstate.drop(f)
3095 else: 3096 else:
3096 excluded_files.append(f) 3097 excluded_files.append(f)
3099 repo.dirstate.drop(f) 3100 repo.dirstate.drop(f)
3100 for f in actions['remove'][0]: 3101 for f in actions['remove'][0]:
3101 audit_path(f) 3102 audit_path(f)
3102 if interactive: 3103 if interactive:
3103 choice = repo.ui.promptchoice( 3104 choice = repo.ui.promptchoice(
3104 _("remove added file %s (Yn)?$$ &Yes $$ &No") % f) 3105 _("remove added file %s (Yn)?$$ &Yes $$ &No") % uipathfn(f))
3105 if choice == 0: 3106 if choice == 0:
3106 prntstatusmsg('remove', f) 3107 prntstatusmsg('remove', f)
3107 doremove(f) 3108 doremove(f)
3108 else: 3109 else:
3109 excluded_files.append(f) 3110 excluded_files.append(f)