diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -733,6 +733,46 @@ def remove(ui, repo, file, *files): """remove the specified files on the next commit""" repo.remove(relpath(repo, (file,) + files)) +def revert(ui, repo, *names, **opts): + """revert modified files or dirs back to their unmodified states""" + node = opts['rev'] and repo.lookup(opts['rev']) or repo.changelog.tip() + root = os.path.realpath(repo.root) + def trimpath(p): + p = os.path.realpath(p) + if p.startswith(root): + rest = p[len(root):] + if not rest: + return rest + if p.startswith(os.sep): + return rest[1:] + return p + relnames = map(trimpath, names or [os.getcwd()]) + chosen = {} + def choose(name): + def body(name): + for r in relnames: + if not name.startswith(r): continue + rest = name[len(r):] + if not rest: return r, True + depth = rest.count(os.sep) + if not r: + if depth == 0 or not opts['nonrecursive']: return r, True + elif rest[0] == os.sep: + if depth == 1 or not opts['nonrecursive']: return r, True + return None, False + relname, ret = body(name) + if ret: + chosen[relname] = 1 + return ret + + r = repo.update(node, False, True, choose, False) + for n in relnames: + if n not in chosen: + ui.warn('error: no matches for %s\n' % n) + r = 1 + sys.stdout.flush() + return r + def root(ui, repo): """print the root (top) of the current working dir""" ui.write(repo.root + "\n") @@ -889,6 +929,10 @@ table = { 'hg rawcommit [options] [files]'), "recover": (recover, [], "hg recover"), "remove|rm": (remove, [], "hg remove [files]"), + "revert": (revert, + [("n", "nonrecursive", None, "don't recurse into subdirs"), + ("r", "rev", "", "revision")], + "hg revert [files|dirs]"), "root": (root, [], "hg root"), "serve": (serve, [('p', 'port', 8000, 'listen port'), ('a', 'address', '', 'interface address'),