Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/commands.py @ 2029:d436b21b20dc
rewrite revert command. fix issues 93, 123, 147.
new version does these things:
- saves backup copies of modified files (issue 147)
- prints output like other commands, and errors when files not found
(issue 123)
- marks files added/removed (issue 93)
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Fri, 31 Mar 2006 10:37:25 -0800 |
parents | a59da8cc35e4 |
children | e3280d350792 c9226bcc288d |
comparison
equal
deleted
inserted
replaced
2028:1f1fc418a96c | 2029:d436b21b20dc |
---|---|
41 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']] | 41 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']] |
42 cwd = '' | 42 cwd = '' |
43 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), | 43 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), |
44 opts.get('exclude'), head) | 44 opts.get('exclude'), head) |
45 | 45 |
46 def makewalk(repo, pats, opts, node=None, head=''): | 46 def makewalk(repo, pats, opts, node=None, head='', badmatch=None): |
47 files, matchfn, anypats = matchpats(repo, pats, opts, head) | 47 files, matchfn, anypats = matchpats(repo, pats, opts, head) |
48 exact = dict(zip(files, files)) | 48 exact = dict(zip(files, files)) |
49 def walk(): | 49 def walk(): |
50 for src, fn in repo.walk(node=node, files=files, match=matchfn): | 50 for src, fn in repo.walk(node=node, files=files, match=matchfn, |
51 badmatch=None): | |
51 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact | 52 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact |
52 return files, matchfn, walk() | 53 return files, matchfn, walk() |
53 | 54 |
54 def walk(repo, pats, opts, node=None, head=''): | 55 def walk(repo, pats, opts, node=None, head='', badmatch=None): |
55 files, matchfn, results = makewalk(repo, pats, opts, node, head) | 56 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch) |
56 for r in results: | 57 for r in results: |
57 yield r | 58 yield r |
58 | 59 |
59 def walkchangerevs(ui, repo, pats, opts): | 60 def walkchangerevs(ui, repo, pats, opts): |
60 '''Iterate over files and the revs they changed in. | 61 '''Iterate over files and the revs they changed in. |
2001 requested revision. Files that changed between either parent are | 2002 requested revision. Files that changed between either parent are |
2002 marked as changed for the next commit and a commit must be | 2003 marked as changed for the next commit and a commit must be |
2003 performed before any further updates are allowed. | 2004 performed before any further updates are allowed. |
2004 """ | 2005 """ |
2005 return update(ui, repo, node=node, merge=True, **opts) | 2006 return update(ui, repo, node=node, merge=True, **opts) |
2006 | 2007 |
2007 def outgoing(ui, repo, dest="default-push", **opts): | 2008 def outgoing(ui, repo, dest="default-push", **opts): |
2008 """show changesets not found in destination | 2009 """show changesets not found in destination |
2009 | 2010 |
2010 Show changesets not found in the specified destination repository or | 2011 Show changesets not found in the specified destination repository or |
2011 the default push location. These are the changesets that would be pushed | 2012 the default push location. These are the changesets that would be pushed |
2086 ui.status(_("not updating, since new heads added\n")) | 2087 ui.status(_("not updating, since new heads added\n")) |
2087 if modheads > 1: | 2088 if modheads > 1: |
2088 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n")) | 2089 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n")) |
2089 else: | 2090 else: |
2090 ui.status(_("(run 'hg update' to get a working copy)\n")) | 2091 ui.status(_("(run 'hg update' to get a working copy)\n")) |
2091 | 2092 |
2092 def pull(ui, repo, source="default", **opts): | 2093 def pull(ui, repo, source="default", **opts): |
2093 """pull changes from the specified source | 2094 """pull changes from the specified source |
2094 | 2095 |
2095 Pull changes from a remote repository to a local one. | 2096 Pull changes from a remote repository to a local one. |
2096 | 2097 |
2284 | 2285 |
2285 In its default mode, it reverts any uncommitted modifications made | 2286 In its default mode, it reverts any uncommitted modifications made |
2286 to the named files or directories. This restores the contents of | 2287 to the named files or directories. This restores the contents of |
2287 the affected files to an unmodified state. | 2288 the affected files to an unmodified state. |
2288 | 2289 |
2290 Modified files have backup copies saved before revert. To disable | |
2291 backups, use --no-backup. To change the name of backup files, use | |
2292 --backup to give a format string. | |
2293 | |
2289 Using the -r option, it reverts the given files or directories to | 2294 Using the -r option, it reverts the given files or directories to |
2290 their state as of an earlier revision. This can be helpful to "roll | 2295 their state as of an earlier revision. This can be helpful to "roll |
2291 back" some or all of a change that should not have been committed. | 2296 back" some or all of a change that should not have been committed. |
2292 | 2297 |
2293 Revert modifies the working directory. It does not commit any | 2298 Revert modifies the working directory. It does not commit any |
2298 | 2303 |
2299 If names are given, all files matching the names are reverted. | 2304 If names are given, all files matching the names are reverted. |
2300 | 2305 |
2301 If no arguments are given, all files in the repository are reverted. | 2306 If no arguments are given, all files in the repository are reverted. |
2302 """ | 2307 """ |
2303 node = opts['rev'] and repo.lookup(opts['rev']) or \ | 2308 parent = repo.dirstate.parents()[0] |
2304 repo.dirstate.parents()[0] | 2309 node = opts['rev'] and repo.lookup(opts['rev']) or parent |
2305 | 2310 mf = repo.manifest.read(repo.changelog.read(node)[0]) |
2306 files, choose, anypats = matchpats(repo, pats, opts) | 2311 |
2307 modified, added, removed, deleted, unknown = repo.changes(match=choose) | 2312 def backup(name, exact): |
2308 repo.forget(added) | 2313 bakname = make_filename(repo, repo.changelog, |
2309 repo.undelete(removed) | 2314 opts['backup_name'] or '%p.orig', |
2310 | 2315 node=parent, pathname=name) |
2311 return repo.update(node, False, True, choose, False) | 2316 if os.path.exists(name): |
2317 # if backup already exists and is same as backup we want | |
2318 # to make, do nothing | |
2319 if os.path.exists(bakname): | |
2320 if repo.wread(name) == repo.wread(bakname): | |
2321 return | |
2322 raise util.Abort(_('cannot save current version of %s - ' | |
2323 '%s exists and differs') % | |
2324 (name, bakname)) | |
2325 ui.status(('saving current version of %s as %s\n') % | |
2326 (name, bakname)) | |
2327 shutil.copyfile(name, bakname) | |
2328 shutil.copymode(name, bakname) | |
2329 | |
2330 wlock = repo.wlock() | |
2331 | |
2332 entries = [] | |
2333 names = {} | |
2334 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key): | |
2335 names[abs] = True | |
2336 entries.append((abs, rel, exact)) | |
2337 | |
2338 changes = repo.changes(match=names.has_key, wlock=wlock) | |
2339 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) | |
2340 | |
2341 revert = ([], _('reverting %s\n')) | |
2342 add = ([], _('adding %s\n')) | |
2343 remove = ([], _('removing %s\n')) | |
2344 forget = ([], _('forgetting %s\n')) | |
2345 undelete = ([], _('undeleting %s\n')) | |
2346 update = {} | |
2347 | |
2348 disptable = ( | |
2349 # dispatch table: | |
2350 # file state | |
2351 # action if in target manifest | |
2352 # action if not in target manifest | |
2353 # make backup if in target manifest | |
2354 # make backup if not in target manifest | |
2355 (modified, revert, remove, True, True), | |
2356 (added, revert, forget, True, True), | |
2357 (removed, undelete, None, False, False), | |
2358 (deleted, revert, remove, False, False), | |
2359 (unknown, add, None, True, False), | |
2360 ) | |
2361 | |
2362 for abs, rel, exact in entries: | |
2363 def handle(xlist, dobackup): | |
2364 xlist[0].append(abs) | |
2365 if dobackup and not opts['no_backup']: | |
2366 backup(rel, exact) | |
2367 if ui.verbose or not exact: | |
2368 ui.status(xlist[1] % rel) | |
2369 for table, hitlist, misslist, backuphit, backupmiss in disptable: | |
2370 if abs not in table: continue | |
2371 # file has changed in dirstate | |
2372 if abs in mf: | |
2373 handle(hitlist, backuphit) | |
2374 elif misslist is not None: | |
2375 handle(misslist, backupmiss) | |
2376 else: | |
2377 if exact: ui.warn(_('file not managed: %s\n' % rel)) | |
2378 break | |
2379 else: | |
2380 # file has not changed in dirstate | |
2381 if node == parent: | |
2382 if exact: ui.warn(_('no changes needed to %s\n' % rel)) | |
2383 continue | |
2384 if abs not in mf: | |
2385 remove[0].append(abs) | |
2386 update[abs] = True | |
2387 | |
2388 repo.dirstate.forget(forget[0]) | |
2389 r = repo.update(node, False, True, update.has_key, False, wlock=wlock) | |
2390 repo.dirstate.update(add[0], 'a') | |
2391 repo.dirstate.update(undelete[0], 'n') | |
2392 repo.dirstate.update(remove[0], 'r') | |
2393 return r | |
2312 | 2394 |
2313 def root(ui, repo): | 2395 def root(ui, repo): |
2314 """print the root (top) of the current working dir | 2396 """print the root (top) of the current working dir |
2315 | 2397 |
2316 Print the root directory of the current repository. | 2398 Print the root directory of the current repository. |
2927 ('X', 'exclude', [], _('exclude names matching the given patterns'))], | 3009 ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
2928 _('hg rename [OPTION]... SOURCE... DEST')), | 3010 _('hg rename [OPTION]... SOURCE... DEST')), |
2929 "^revert": | 3011 "^revert": |
2930 (revert, | 3012 (revert, |
2931 [('r', 'rev', '', _('revision to revert to')), | 3013 [('r', 'rev', '', _('revision to revert to')), |
2932 ('I', 'include', [], _('include names matching the given patterns')), | 3014 ('', 'backup-name', '', _('save backup with formatted name')), |
2933 ('X', 'exclude', [], _('exclude names matching the given patterns'))], | 3015 ('', 'no-backup', None, _('do not save backup copies of files')), |
3016 ('I', 'include', [], _('include names matching given patterns')), | |
3017 ('X', 'exclude', [], _('exclude names matching given patterns'))], | |
2934 _('hg revert [-r REV] [NAME]...')), | 3018 _('hg revert [-r REV] [NAME]...')), |
2935 "root": (root, [], _('hg root')), | 3019 "root": (root, [], _('hg root')), |
2936 "^serve": | 3020 "^serve": |
2937 (serve, | 3021 (serve, |
2938 [('A', 'accesslog', '', _('name of access log file to write to')), | 3022 [('A', 'accesslog', '', _('name of access log file to write to')), |