Mercurial > hg
comparison mercurial/commands.py @ 16304:a740fa28d718
revert: move bulk of revert command from commands to cmdutil
This revision has no functionality change. The code on the original
commands.revert() function has been split. The first part of the
original code, which checks that the command inputs are correct
remains in commands.revert(). The rest of the function, which performs
the actual revert operation has been moved into cmdutil.revert().
The purpose of this change is to make it easier to perform a revert
operation, from other parts of the code. This may be used to implement
reverting of subrepos.
author | Angel Ezquerra <angel.ezquerra@gmail.com> |
---|---|
date | Wed, 28 Mar 2012 11:42:17 +0200 |
parents | 5d75eb8568d1 |
children | 329887a7074c |
comparison
equal
deleted
inserted
replaced
16295:ba42eb722bb3 | 16304:a740fa28d718 |
---|---|
4777 # revert after merge is a trap for new users (issue2915) | 4777 # revert after merge is a trap for new users (issue2915) |
4778 raise util.Abort(_('uncommitted merge with no revision specified'), | 4778 raise util.Abort(_('uncommitted merge with no revision specified'), |
4779 hint=_('use "hg update" or see "hg help revert"')) | 4779 hint=_('use "hg update" or see "hg help revert"')) |
4780 | 4780 |
4781 ctx = scmutil.revsingle(repo, opts.get('rev')) | 4781 ctx = scmutil.revsingle(repo, opts.get('rev')) |
4782 node = ctx.node() | |
4783 | 4782 |
4784 if not pats and not opts.get('all'): | 4783 if not pats and not opts.get('all'): |
4785 msg = _("no files or directories specified") | 4784 msg = _("no files or directories specified") |
4786 if p2 != nullid: | 4785 if p2 != nullid: |
4787 hint = _("uncommitted merge, use --all to discard all changes," | 4786 hint = _("uncommitted merge, use --all to discard all changes," |
4788 " or 'hg update -C .' to abort the merge") | 4787 " or 'hg update -C .' to abort the merge") |
4789 raise util.Abort(msg, hint=hint) | 4788 raise util.Abort(msg, hint=hint) |
4790 dirty = util.any(repo.status()) | 4789 dirty = util.any(repo.status()) |
4790 node = ctx.node() | |
4791 if node != parent: | 4791 if node != parent: |
4792 if dirty: | 4792 if dirty: |
4793 hint = _("uncommitted changes, use --all to discard all" | 4793 hint = _("uncommitted changes, use --all to discard all" |
4794 " changes, or 'hg update %s' to update") % ctx.rev() | 4794 " changes, or 'hg update %s' to update") % ctx.rev() |
4795 else: | 4795 else: |
4799 hint = _("uncommitted changes, use --all to discard all changes") | 4799 hint = _("uncommitted changes, use --all to discard all changes") |
4800 else: | 4800 else: |
4801 hint = _("use --all to revert all files") | 4801 hint = _("use --all to revert all files") |
4802 raise util.Abort(msg, hint=hint) | 4802 raise util.Abort(msg, hint=hint) |
4803 | 4803 |
4804 mf = ctx.manifest() | 4804 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts) |
4805 if node == parent: | |
4806 pmf = mf | |
4807 else: | |
4808 pmf = None | |
4809 | |
4810 # need all matching names in dirstate and manifest of target rev, | |
4811 # so have to walk both. do not print errors if files exist in one | |
4812 # but not other. | |
4813 | |
4814 names = {} | |
4815 | |
4816 wlock = repo.wlock() | |
4817 try: | |
4818 # walk dirstate. | |
4819 | |
4820 m = scmutil.match(repo[None], pats, opts) | |
4821 m.bad = lambda x, y: False | |
4822 for abs in repo.walk(m): | |
4823 names[abs] = m.rel(abs), m.exact(abs) | |
4824 | |
4825 # walk target manifest. | |
4826 | |
4827 def badfn(path, msg): | |
4828 if path in names: | |
4829 return | |
4830 if path in repo[node].substate: | |
4831 ui.warn("%s: %s\n" % (m.rel(path), | |
4832 'reverting subrepos is unsupported')) | |
4833 return | |
4834 path_ = path + '/' | |
4835 for f in names: | |
4836 if f.startswith(path_): | |
4837 return | |
4838 ui.warn("%s: %s\n" % (m.rel(path), msg)) | |
4839 | |
4840 m = scmutil.match(repo[node], pats, opts) | |
4841 m.bad = badfn | |
4842 for abs in repo[node].walk(m): | |
4843 if abs not in names: | |
4844 names[abs] = m.rel(abs), m.exact(abs) | |
4845 | |
4846 m = scmutil.matchfiles(repo, names) | |
4847 changes = repo.status(match=m)[:4] | |
4848 modified, added, removed, deleted = map(set, changes) | |
4849 | |
4850 # if f is a rename, also revert the source | |
4851 cwd = repo.getcwd() | |
4852 for f in added: | |
4853 src = repo.dirstate.copied(f) | |
4854 if src and src not in names and repo.dirstate[src] == 'r': | |
4855 removed.add(src) | |
4856 names[src] = (repo.pathto(src, cwd), True) | |
4857 | |
4858 def removeforget(abs): | |
4859 if repo.dirstate[abs] == 'a': | |
4860 return _('forgetting %s\n') | |
4861 return _('removing %s\n') | |
4862 | |
4863 revert = ([], _('reverting %s\n')) | |
4864 add = ([], _('adding %s\n')) | |
4865 remove = ([], removeforget) | |
4866 undelete = ([], _('undeleting %s\n')) | |
4867 | |
4868 disptable = ( | |
4869 # dispatch table: | |
4870 # file state | |
4871 # action if in target manifest | |
4872 # action if not in target manifest | |
4873 # make backup if in target manifest | |
4874 # make backup if not in target manifest | |
4875 (modified, revert, remove, True, True), | |
4876 (added, revert, remove, True, False), | |
4877 (removed, undelete, None, False, False), | |
4878 (deleted, revert, remove, False, False), | |
4879 ) | |
4880 | |
4881 for abs, (rel, exact) in sorted(names.items()): | |
4882 mfentry = mf.get(abs) | |
4883 target = repo.wjoin(abs) | |
4884 def handle(xlist, dobackup): | |
4885 xlist[0].append(abs) | |
4886 if (dobackup and not opts.get('no_backup') and | |
4887 os.path.lexists(target)): | |
4888 bakname = "%s.orig" % rel | |
4889 ui.note(_('saving current version of %s as %s\n') % | |
4890 (rel, bakname)) | |
4891 if not opts.get('dry_run'): | |
4892 util.rename(target, bakname) | |
4893 if ui.verbose or not exact: | |
4894 msg = xlist[1] | |
4895 if not isinstance(msg, basestring): | |
4896 msg = msg(abs) | |
4897 ui.status(msg % rel) | |
4898 for table, hitlist, misslist, backuphit, backupmiss in disptable: | |
4899 if abs not in table: | |
4900 continue | |
4901 # file has changed in dirstate | |
4902 if mfentry: | |
4903 handle(hitlist, backuphit) | |
4904 elif misslist is not None: | |
4905 handle(misslist, backupmiss) | |
4906 break | |
4907 else: | |
4908 if abs not in repo.dirstate: | |
4909 if mfentry: | |
4910 handle(add, True) | |
4911 elif exact: | |
4912 ui.warn(_('file not managed: %s\n') % rel) | |
4913 continue | |
4914 # file has not changed in dirstate | |
4915 if node == parent: | |
4916 if exact: | |
4917 ui.warn(_('no changes needed to %s\n') % rel) | |
4918 continue | |
4919 if pmf is None: | |
4920 # only need parent manifest in this unlikely case, | |
4921 # so do not read by default | |
4922 pmf = repo[parent].manifest() | |
4923 if abs in pmf and mfentry: | |
4924 # if version of file is same in parent and target | |
4925 # manifests, do nothing | |
4926 if (pmf[abs] != mfentry or | |
4927 pmf.flags(abs) != mf.flags(abs)): | |
4928 handle(revert, False) | |
4929 else: | |
4930 handle(remove, False) | |
4931 | |
4932 if not opts.get('dry_run'): | |
4933 def checkout(f): | |
4934 fc = ctx[f] | |
4935 repo.wwrite(f, fc.data(), fc.flags()) | |
4936 | |
4937 audit_path = scmutil.pathauditor(repo.root) | |
4938 for f in remove[0]: | |
4939 if repo.dirstate[f] == 'a': | |
4940 repo.dirstate.drop(f) | |
4941 continue | |
4942 audit_path(f) | |
4943 try: | |
4944 util.unlinkpath(repo.wjoin(f)) | |
4945 except OSError: | |
4946 pass | |
4947 repo.dirstate.remove(f) | |
4948 | |
4949 normal = None | |
4950 if node == parent: | |
4951 # We're reverting to our parent. If possible, we'd like status | |
4952 # to report the file as clean. We have to use normallookup for | |
4953 # merges to avoid losing information about merged/dirty files. | |
4954 if p2 != nullid: | |
4955 normal = repo.dirstate.normallookup | |
4956 else: | |
4957 normal = repo.dirstate.normal | |
4958 for f in revert[0]: | |
4959 checkout(f) | |
4960 if normal: | |
4961 normal(f) | |
4962 | |
4963 for f in add[0]: | |
4964 checkout(f) | |
4965 repo.dirstate.add(f) | |
4966 | |
4967 normal = repo.dirstate.normallookup | |
4968 if node == parent and p2 == nullid: | |
4969 normal = repo.dirstate.normal | |
4970 for f in undelete[0]: | |
4971 checkout(f) | |
4972 normal(f) | |
4973 | |
4974 finally: | |
4975 wlock.release() | |
4976 | 4805 |
4977 @command('rollback', dryrunopts + | 4806 @command('rollback', dryrunopts + |
4978 [('f', 'force', False, _('ignore safety measures'))]) | 4807 [('f', 'force', False, _('ignore safety measures'))]) |
4979 def rollback(ui, repo, **opts): | 4808 def rollback(ui, repo, **opts): |
4980 """roll back the last transaction (dangerous) | 4809 """roll back the last transaction (dangerous) |